Я создал файл данных в следующем формате:
0.1
Analytic value = 340.347685734
Approximated value = 332.45634555
--
0.2
Analytic value = 340.936745872
Approximated value = 332.57893789
--
0.3
... and so on
Я хочу построить аналитические и приблизительные значения в matplotlib/gnuplot в зависимости от входного параметра (0,1, 0,2 и т. д.). Обычно перед созданием файла данных я использую для их создания скрипт awk, который помещает три значения в три столбца, что очень легко построить. Однако здесь я случайно сгенерировал файл данных в другом формате. Как я могу преобразовать этот текстовый файл в следующий (возможно, используя регулярное выражение или awk!):
0.1 340.347685734 332.45634555
0.2 340.936745872 332.57893789
0.3 ... and so on
Или есть способ построить данные без преобразования формата с помощью gnuplot/matplotlib?
Обновлено: Я попытался сделать это с помощью python3. Ниже приведен мой код:
file = open("myFile.dat",'r')
newFile = open("newFile.dat", 'a')
for i in range(4000):
col1 = file.readline().split[-1]
col2 = file.readline().split[-1]
col3 = file.readline().split[-1]
_ = file.readline().split[-1]
line = col1 + " " + col2 + " " + col3
newFile.write(line)
Однако я получил некоторую ошибку TypeError: 'builtin_function_or_method' object is not subscriptable
, которую я не понял, и я думаю, что это очень неэффективный код. Поэтому я и спросил в SE. Все решения, представленные до сих пор, работают достаточно хорошо. Я отметил решение awk
как принятый ответ, потому что оно простое и элегантное. Кроме того, я ценю решение, использующее только gnuplot, которое также раскрывает для меня одну сторону gnuplot.
Выглядит достаточно легко сделать с Regex. В чем проблема придумать регулярное выражение, которое это делает?
Даже Regex вообще не нужен. 1. Замените Analytic value =
ничем. 2. Замените Approximated value =
ничем. 3. Замените \n
пробелом. 4. Замените --
на \n
Пожалуйста, отредактируйте свой вопрос (без комментариев): Что вы искали и что нашли? Что вы пробовали, и как это не удалось?
Здесь не нужно регулярное выражение. Всего 4 простых замены:
Две замены для нежелательного текста, одна замена для удаления разрывов строк и одна замена для повторной вставки разрыва строки.
file = """0.1
Analytic value = 340.347685734
Approximated value = 332.45634555
--
0.2
Analytic value = 340.936745872
Approximated value = 332.57893789
--
0.3
... and so on
"""
file = file.replace("Analytic value = ","")
file = file.replace("Approximated value = ","")
file = file.replace("\n"," ")
file = file.replace("-- ","\n")
print(file)
Результат:
0.1 340.347685734 332.45634555
0.2 340.936745872 332.57893789
0.3 ... and so on
Я бы использовал GNU AWK
для этой задачи следующим образом, пусть file.txt
контент будет
0.1
Analytic value = 340.347685734
Approximated value = 332.45634555
--
0.2
Analytic value = 340.936745872
Approximated value = 332.57893789
--
затем
awk '/^--$/{print "";next}{printf "%s ",$NF}' file.txt
нет вывода
0.1 340.347685734 332.45634555
0.2 340.936745872 332.57893789
Объяснение: для строки --
просто напечатайте новую строку и перейдите к следующей, для всех остальных строк выведите последнее поле, за которым следует пробел, а не новую строку. Если вы хотите узнать больше о NF
, прочитайте 8 мощных встроенных переменных Awk — FS, OFS, RS, ORS, NR, NF, FILENAME, FNR
(проверено в GNU Awk 5.1.0)
Есть много способов решить эту проблему, и выбор, среди прочего, будет зависеть от размера файла. Вот простое решение для случая, когда вы не можете загрузить весь файл сразу - вам нужно обрабатывать его построчно,
raw_data_file = 'data.txt'
out_data_file = 'data_final.txt'
counter = 0
with open(raw_data_file, 'r') as fin, open(out_data_file, 'w') as fout:
temp_line = []
for line in fin:
if counter == 0:
# First column
temp_line.append(line.strip())
counter += 1
continue
elif counter == 1:
# Analytic value column
temp_line.append(line.strip().split()[-1])
counter += 1
continue
elif counter == 2:
# Approximate value column
temp_line.append(line.strip().split()[-1])
counter += 1
elif counter == 3:
# Skip the -- and reset the counter
counter = 0
continue
# Write the rearranged data to file
fout.write((' ').join(temp_line))
fout.write('\n')
temp_line = []
Обратите внимание, что это решение тесно связано со структурой предоставленного вами файла.
Или есть способ построить данные без преобразования формата с помощью gnuplot/matplotlib?
Да, есть! Вот независимое от платформы решение только для gnuplot. Нет необходимости во внешних дополнительных инструментах подготовки данных.
Если вы рисуете из файла, пропустите раздел $Data <<EOD ... EOD
и используйте plot 'yourFile.dat' ...
.
Скрипт: (работает для gnuplot>=5.0.6, март 2017 г.)
### plot special data format
reset session
$Data <<EOD
0.1
Analytic value = 340.347685734
Approximated value = 332.45634555
--
0.2
Analytic value = 340.936745872
Approximated value = 332.57893789
--
0.3
Analytic value = 341.936745872
Approximated value = 333.57893789
EOD
set datafile missing NaN
set key out
myFilter(colD,colF,valF) = strcol(colF) eq valF ? column(colD) : NaN
plot $Data u (valid(1)?x0=$1:x0):(myFilter(4,1,"Analytic")) w lp pt 7 lc "red" ti "analytic", \
'' u (valid(1)?x0=$1:x0):(myFilter(4,1,"Approximated")) w lp pt 7 lc "blue" ti "approximated"
### end of script
Результат:
Используя любой awk:
$ awk '{n=(NR%4); val[n]=$NF} n==0{print val[1], val[2], val[3]}' file
0.1 340.347685734 332.45634555
0.2 340.936745872 332.57893789
Попробуйте это:
awk '/^[0-9]+\.[0-9]+$/ {val = $0} /Analytic value =/ {split($0, a, " = "); analytic = a[3]} /Approximated value =/ {split($0, a, " = "); approx = a[3]; print val, analytic, approx}' your_file > output_file