I'm running Python 3.9.2 on a Raspberry Pi and I've written a script that will read water temperatures from my boiler and write them to a CSV file. However, each data item in the output file appears on a new line.
Here's my code:
from subprocess import check_output
import csv
header = ['Flow', 'Return']
cmd = ["/usr/bin/ebusctl", "read", "-f"]
data = [
[float(check_output([*cmd, "FlowTemp", "temp"]))],
[float(check_output([*cmd, "ReturnTemp", "temp"]))]
]
with open('sandbox.csv', 'w', encoding='utf8', newline='') as f:
writer = csv.writer(f)
writer.writerow(header)
writer.writerows(data)
And here's the content of sandbox.csv:
Flow,Return
57.19
43.12
How could I fix this?
CodePudding user response:
The issue is that you are passing a list of lists to the writerows()
method, but you only want to pass a list of values. To fix this, you can use the extend()
method to add the values from each sublist in data to the list of rows that will be written to the CSV file, like this:
from subprocess import check_output
import csv
header = ['Flow', 'Return']
cmd = ["/usr/bin/ebusctl", "read", "-f"]
data = [
[float(check_output([*cmd, "FlowTemp", "temp"]))],
[float(check_output([*cmd, "ReturnTemp", "temp"]))]
]
rows = []
for row in data:
rows.extend(row)
with open('sandbox.csv', 'w', encoding='utf8', newline='') as f:
writer = csv.writer(f)
writer.writerow(header)
writer.writerow(rows)
This should result in a CSV file with the correct format.
CodePudding user response:
CSV files contain one record per row.
The writerow
method writes one record to the file which it expects to be represented as one list or tuple of values, e.g. for one record a, b, c
:
[a, b, c]
The writerows
method does the same for multiple records at once, which it expects to be represented as a list or tuple of records, e.g. for two records a, b, c
and x, y, z
:
[[a, b, c], [x, y, z]]
The data you are passing to writerows
is structured like this:
[[Flow], [Return]]
This means that writerows
will write two records to the file (each in one line), each containing only one value.
If you intend Flow, Return
to be one record (written to one line), your data needs to be structured differently:
Either you create
data = [Flow, Return]
(a single record) and pass it towriterow
.Or you create
data = [[Flow, Return]]
(a list of records, containing only one record) and pass it towriterows
.
CodePudding user response:
To fix the issue with each data item appearing on a new line in your CSV file, you will need to modify the way you are writing the data to the file. Currently, you are using the "writerows" method of the CSV writer to write the data, which writes each element of the "data" list as a separate row in the CSV file.
To write the data as a single row in the CSV file, you will need to modify your code to use the "writerow" method of the CSV writer instead. This method takes a single argument, which is a list of values to write to the current row in the CSV file.
Here is how you could modify your code to use the "writerow" method to write the data as a single row in the CSV file:
from subprocess import check_output
import csv
header = ['Flow', 'Return']
cmd = ["/usr/bin/ebusctl", "read", "-f"]
data = [
float(check_output([*cmd, "FlowTemp", "temp"])),
float(check_output([*cmd, "ReturnTemp", "temp"]))
]
with open('sandbox.csv', 'w', encoding='utf8', newline='') as f:
writer = csv.writer(f)
writer.writerow(header)
writer.writerow(data)
In this modified code, the "data" variable is defined as a list of the values to write to the CSV file, rather than a list of lists. This allows the "writerow" method to write the values as a single row in the CSV file, rather than as separate rows.