Ich bin nicht vertraut mit exportierten Plot-Daten von LTspice, also gehe ich davon aus, dass die Formatierung der von Ihnen bereitgestellten Beispielzeilen für alle Zeiten gültig ist.
Mit Blick auf die IO-Tools Abschnitt der Pandas-0.18-Dokumentation (here), sehe ich keine gebrauchsfertige Parser-Dienstprogramm für Ihr Datenformat. Das erste, was einem in den Sinn kommt, ist das eigene Parsen und Vorbereiten, bevor man einen Pandas-Datenrahmen ausfüllt.
Ich gehe davon aus, dass der entscheidende Teil Ihres Problems ist, die Datendatei zu analysieren, es ist eine Weile her, seit ich mit Pandas und Matplotlib gespielt habe, also erwarten Sie Fehler in Bezug auf diese.
Beispiel
Hier ist eine schnelle & schmutzig python3 Skript Ihre Daten in eine Liste von Wörterbüchern zu analysieren, eine Pandas Datenrahmen mit ihm bauen und zeichnen sie die plot
Methode der Datenrahmen verwenden. Ich habe versucht, die Schritte in den Kommentaren zu erklären:
# ltspice.py
""" Use it as:
> python3 ltspice.py /path/to/datafile """
import pandas
import sys
data_header = "Time Gain Degree".split()
# Valid line example:
# 5.00000000000000e+006\t(2.84545891331278e+001dB,8.85405282381414e+001°)
def parse_line(linestr):
# ValueError and IndexError exceptions are used to mark the failure of
# the parse.
try:
# First we split at the '\t' character. This will raise ValueError if
# there is no \t character or there is more than 1 \t
timestr, rest = linestr.split('\t')
# Then we find the indexes of the '(' and ')' in the rest string.
parenst, parenend = (rest.find('(')+1, rest.find(')'))
if (parenst == -1) or (parenend == -1):
# find() method returns -1 if nothing is found, I raise ValueError
# to mark it as a parsing failure
raise ValueError
# rest[parenst:parenend] returns the string inside parens. split method
# splits the string into words separated by the given character (i.e.
# ',')
powstr, degstr = rest[parenst:parenend].split(',')
# converting strings into floats. Replacing units as necessary.
time = float(timestr)
power = float(powstr.replace('dB', ''))
# this will fail with python 2.x
deg = float(degstr.replace('°', ''))
# You can use dict() instead of tuple()
return tuple(zip(data_header, (time, power, deg)))
except (ValueError,IndexError) as e:
return None
def fileparser(fname):
""" A generator function to return a parsed line on each iteration """
with open(fname, mode='r') as fin:
for line in fin:
res = parse_line(line)
if res is not None:
yield res
def create_dataframe(fname):
p = fileparser(fname)
# rec is a tuple of 2-tuples that can be used to directly build a python
# dictionary
recs = [dict(rec) for rec in p]
return pandas.DataFrame.from_records(recs)
if __name__ == '__main__':
data_fname = sys.argv[1]
df = create_dataframe(data_fname)
ax = df.plot(x='Time', y='Gain')
fig = ax.get_figure()
fig.savefig('df.png')
Sie kopieren in einen Texteditor diesen Code und als ltspice.py
und führen Sie es mit python3 ltspice.py yourdata.dat
von Ihrem Terminal speichern.
Beachten Sie, dass die Funktion parse_line
tatsächlich ein Tupel von 2-Tupeln in Form von ('Schlüssel', Wert) zurückgibt, wobei 'Schlüssel' den Spaltennamen darstellt. Dieser Wert wird dann verwendet, um die Liste der Wörterbücher in der create_dataframe
-Funktion zu erstellen.
Extra-
Ich schrieb ein anderes Skript, das Verhalten zu testen:
# test.py
import random
from ltspice import fileparser
def gen_data():
time = random.randint(0,100)*1e6
db = random.lognormvariate(2,0.5)
degree = random.uniform(0,360)
# this is necessary for comparing parsed values with values generated
truncate = lambda x: float('{:.15e}'.format(x))
return (truncate(time),truncate(db),truncate(degree))
def format_data_line(datatpl):
time, db, degree = datatpl[0], datatpl[1], datatpl[2]
formatted = "{0:.15e}\t({1:.15e}dB,{2:.15e}°)\n"
return formatted.format(time, db, degree)
def gen_ignore_line():
tmpl = "Step Information: L={}n (Run:{}/{})\n"
l = random.randint(100,1000)
r2 = random.randint(1,100)
r1 = random.randint(0,r2)
return tmpl.format(l,r1,r2)
def create_test_file(fname, valid_count, invalid_count):
""" Creates a test file containing data lines mixed with lines to be
ignored. Returns the data created.
valid_count: number of the actual data lines
invalid_count: number of the to-be-ignored lines
"""
header = 'Time Gain Degree'.split()
data = []
formatteddatalines = []
for i in range(valid_count):
unfmtdata = gen_data()
data.append(tuple(zip(header, unfmtdata)))
formatteddatalines.append(format_data_line(unfmtdata))
invalidlines = []
for i in range(invalid_count):
invalidlines.append(gen_ignore_line())
lines = formatteddatalines + invalidlines
random.shuffle(lines)
with open(fname, mode='w') as fout:
fout.writelines(lines)
return data
if __name__ == '__main__':
fname = 'test.data'
validcnt = 10
invalidcnt = 2
validdata = create_test_file(fname, validcnt, invalidcnt)
parseddata = [data for data in fileparser(fname)]
# Note: this check ignores duplicates.
assert(set(validdata) == set(parseddata))
Vielen Dank für diese Lösung, das hat für mich funktioniert! Ich fügte eine Überprüfung jeder Zeile mit 'str.startswith ("Step Information") ' und dadurch die verschiedenen Schritte in eine Liste von DataFrames getrennt, die nun einwandfrei funktioniert – RobertAlpha
Froh, dass es geklappt hat :) Gern geschehen! –