Home > Enterprise >  Formatting txt files using pandas/python
Formatting txt files using pandas/python

Time:06-05

I have a txt file from a lab equipment which saves data in the following format:

Run1 
Selected data
        Time (s)    Charge Q (nC)   Charge density q (nC/g) Mass (g)    
Initial -   21.53   -2.81E-01   -1.41E-03   200.0   
Flow    -   0.00    0.00E 00    0.00E 00    0.0 
Charge (in Coulomb) temporal evolution
3.61    2.44e-11
4.11    2.44e-11
4.61    2.44e-11
5.11    3.66e-11
5.63    3.66e-11
6.14    2.44e-11
6.66    3.66e-11
7.14    3.66e-11
7.67    2.44e-11
8.19    3.66e-11
8.70    2.44e-11
9.20    2.44e-11
9.72    2.44e-11
10.23   2.44e-11
10.73   2.44e-11

Run2 
Selected data
        Time (s)    Charge Q (nC)   Charge density q (nC/g) Mass (g)    
Initial -   21.53   -2.81E-01   -1.41E-03   200.0   
Flow    -   0.00    0.00E 00    0.00E 00    0.0 
Charge (in Coulomb) temporal evolution
3.61    2.44e-11
4.11    2.44e-11
4.61    2.44e-11
5.11    3.66e-11
5.63    3.66e-11
6.14    2.44e-11
6.66    3.66e-11
7.14    3.66e-11
7.67    2.44e-11
8.19    3.66e-11

Run3 
Selected data
        Time (s)    Charge Q (nC)   Charge density q (nC/g) Mass (g)    
Initial -   21.53   -2.81E-01   -1.41E-03   200.0   
Flow    -   0.00    0.00E 00    0.00E 00    0.0 
Charge (in Coulomb) temporal evolution
3.61    2.44e-11
4.11    2.44e-11
4.61    2.44e-11
5.11    3.66e-11
5.63    3.66e-11
6.14    2.44e-11
6.66    3.66e-11
7.14    3.66e-11
7.67    2.44e-11
8.19    3.66e-11
8.70    2.44e-11
9.20    2.44e-11

And i have multiples of these in my test folder. I was looking to simplify and automate the analysis i do on these data sets because for another equipment i had similar success with a simpler code.

What i want to do is extract the 2 column test data for each of the 3 runs from each file with FileName, and export into a commas separated text file with filename = FileName-Run#.txt

What i have done till now is attempt to convert the text file contents into a list of lists and then try and process the numerical data alone into a new csv, but that hasn't worked well since i am unable to detect the length of column data of interest to me.

A couple of other Q-As here helped in that regard including how to run the code on files within a folder, if it works, that is.

I have used a jupyter notebook - i can share the code i have wrote up here if it would be useful, although i am ashamed to show it.

CodePudding user response:

Try this:

import re
from pathlib import Path

input_path = Path("path/to/input_folder")
output_path = Path("path/to/output_folder")
run_name_pattern = re.compile("Run\d ")
data_line_pattern = re.compile("(. ?)  (. ?)")


def write_output(input_file: Path, run_name: str, data: str):
    output_file = output_path / f"{input_file.stem}-{run_name}.csv"
    with output_file.open("w") as fp_out:
        fp_out.write(data)


for input_file in input_path.glob("*.txt"):
    with input_file.open() as fp:
        run_name, data, start_reading = "", "", False

        for line in fp:
            # If a line matches "Run...", start a new run name
            if run_name_pattern.match(line):
                run_name = line.strip()
            # If the line matches "Charge (in Coulomb)...",
            # read in the data, starting with the next line
            elif line.startswith("Charge (in Coulomb) temporal evolution"):
                start_reading = True
            # For the data lines, replace spaces in the middle with a comma
            elif start_reading and line != "\n":
                data  = data_line_pattern.sub(r"\1,\2", line)
            # If we encounter a blank line, that means the end of data.
            # Flush the data to disk.
            elif line == "\n":
                write_output(input_file, run_name, data)
                run_name, data, start_reading = "", "", False
        else:
            # If we have reached the end of the file but there still
            # data we haven't written to disk, flush it
            if data:
                write_output(input_file, run_name, data)

CodePudding user response:

This works:

import csv
import os
import re

# Where the input
PATH_INPUT = "./test.txt"
# Define the output directory
DIR_OUTPUT = "./output"



def is_section_start(line):
    """Function to check to see if a line is the start of a section
    
    The start of a section is defined as starting with "Run"
    """
    return re.match("^Run", line)


def is_data_line(line):
    """Function to check to see if a line is a data line
    
    A data line is defined if a line starts with a number
    """
    return re.match("^\d", line)


def get_data(line):
    """Split data line into the two numbers"""
    split = line.split(" ")
    split = [s for s in split if s]
    return [float(split[0]), float(split[1])]


if __name__ == "__main__":
    # Open up the input file and read data into a dictionary where the key is the run name and the
    # value is a list of list of the numbers.
    output = {}
    with open(PATH_INPUT) as f_in:
        current_section = None
        for line in f_in.readlines():
            line = line.strip()
            if is_section_start(line) and current_section != line:
                current_section = line
                output[current_section] = []
            
            if is_data_line(line):
                output[current_section].append(get_data(line))
    
    # Write data
    for run, data in output.items():
        with open(os.path.join(DIR_OUTPUT, f"{PATH_INPUT}-{run}.txt"), "w") as f_out:
            writer = csv.writer(f_out)
            writer.writerows(data)

CodePudding user response:

There are a lot of very complicated ways to read the data, but I wanted to present a simpler method:

with open('file.txt') as f:
    data = file.read().split('\n\n')

for run in data:
    run = run.split('\n')
    run_num = run[0]
    df = pd.DataFrame(run[6:])[0].str.split(expand=True).astype(float)
    df.columns = ['Charge (in Coulomb)', 'temporal evolution']
    print(run_num)
    print(df)

Output:

Run1
    Charge (in Coulomb)  temporal evolution
0                  3.61        2.440000e-11
1                  4.11        2.440000e-11
2                  4.61        2.440000e-11
3                  5.11        3.660000e-11
4                  5.63        3.660000e-11
5                  6.14        2.440000e-11
6                  6.66        3.660000e-11
7                  7.14        3.660000e-11
8                  7.67        2.440000e-11
9                  8.19        3.660000e-11
10                 8.70        2.440000e-11
11                 9.20        2.440000e-11
12                 9.72        2.440000e-11
13                10.23        2.440000e-11
14                10.73        2.440000e-11
Run2
   Charge (in Coulomb)  temporal evolution
0                 3.61        2.440000e-11
1                 4.11        2.440000e-11
2                 4.61        2.440000e-11
3                 5.11        3.660000e-11
4                 5.63        3.660000e-11
5                 6.14        2.440000e-11
6                 6.66        3.660000e-11
7                 7.14        3.660000e-11
8                 7.67        2.440000e-11
9                 8.19        3.660000e-11
Run3
    Charge (in Coulomb)  temporal evolution
0                  3.61        2.440000e-11
1                  4.11        2.440000e-11
2                  4.61        2.440000e-11
3                  5.11        3.660000e-11
4                  5.63        3.660000e-11
5                  6.14        2.440000e-11
6                  6.66        3.660000e-11
7                  7.14        3.660000e-11
8                  7.67        2.440000e-11
9                  8.19        3.660000e-11
10                 8.70        2.440000e-11
11                 9.20        2.440000e-11
  • Related