How to write Fortran Output as CSV file? - excel

Can any one tell me, how can I write my output of Fortran program in CSV format? So I can open the CSV file in Excel for plotting data.

A slightly simpler version of the write statement could be:
write (1, '(1x, F, 3(",", F))') a(1), a(2), a(3), a(4)
Of course, this only works if your data is numeric or easily repeatable. You can leave the formatting to your spreadsheet program or be more explicit here.

I'd also recommend the csv_file module from FLIBS. Fortran is well equipped to read csv files, but not so much to write them. With the csv_file module, you put
use csv_file
at the beginning of your function/subroutine and then call it with:
call csv_write(unit, value, advance)
where unit = the file unit number, value = the array or scalar value you want to write, and advance = .true. or .false. depending on whether you want to advance to the next line or not.
Sample program:
program write_csv
use csv_file
implicit none
integer :: a(3), b(2)
open(unit=1,file='test.txt',status='unknown')
a = (/1,2,3/)
b = (/4,5/)
call csv_write(1,a,.true.)
call csv_write(1,b,.true.)
end program
output:
1,2,3
4,5
if you instead just want to use the write command, I think you have to do it like this:
write(1,'(I1,A,I1,A,I1)') a(1),',',a(2),',',a(3)
write(1,'(I1,A,I1)') b(1),',',b(2)
which is very convoluted and requires you to know the maximum number of digits your values will have.
I'd strongly suggest using the csv_file module. It's certainly saved me many hours of frustration.

The Intel and gfortran (5.5) compilers recognize:
write(unit,'(*(G0.6,:,","))')array or data structure
which doesn't have excess blanks, and the line can have more than 999 columns.
To remove excess blanks with F95, first write into a character buffer and then use your own CSV_write program to take out the excess blanks, like this:
write(Buf,'(999(G21.6,:,","))')array or data structure
call CSV_write(unit,Buf)
You can also use
write(Buf,*)array or data structure
call CSV_write(unit,Buf)
where your CSV_write program replaces whitespace with "," in Buf. This is problematic in that it doesn't separate character variables unless there are extra blanks (i.e. 'a ','abc ' is OK).

I thought a full simple example without any other library might help. I assume you are working with matrices, since you want to plot from Excel (in any case it should be easy to extend the example).
tl;dr
Print one row at a time in a loop using the format format(1x, *(g0, ", "))
Full story
The purpose of the code below is to write in CSV format (that you can easily import in Excel) a (3x4) matrix.
The important line is the one labeled 101. It sets the format.
program testcsv
IMPLICIT NONE
INTEGER :: i, nrow
REAL, DIMENSION(3,4) :: matrix
! Create a sample matrix
matrix = RESHAPE(source = (/1,2,3,4,5,6,7,8,9,10,11,12/), &
shape = (/ 3, 4 /))
! Store the number of rows
nrow = SIZE(matrix, 1)
! Formatting for CSV
101 format(1x, *(g0, ", "))
! Open connection (i.e. create file where to write)
OPEN(unit = 10, access = "sequential", action = "write", &
status = "replace", file = "data.csv", form = "formatted")
! Loop across rows
do i=1,3
WRITE(10, 101) matrix(i,:)
end do
! Close connection
CLOSE(10)
end program testcsv
We first create the sample matrix. Then store the number of rows in the variable nrow (this is useful when you are not sure of the matrix's dimension beforehand). Skip a second the format statement. What we do next is to open (create or replace) the CSV file, names data.csv. Then we loop over the rows (do statement) of the matrix to write a row at a time (write statement) in the CSV file; rows will be appended one after another.
In more details how the write statement works is: WRITE(U,FMT) WHAT. We write "what" (the i-th row of the matrix: matrix(i,:)), to connection U (the one we created with the open statement), formatting the WHAT according to FMT.
Note that in the example FMT=101, and 101 is the label of our format statement:
format(1x, *(g0, ", "))
what this does is: "1x" insert a white space at the beginning of the row; the "*" is used for unlimited format repetition, which means that the format in the following parentheses is repeated for all the data left in the object we are printing (i.e. all elements in the matrix's row). Thus, each row number is formatted as: 'g0, ", "'.
g is a general format descriptor that handles floats as well as characters, logicals and integers; the trailing 0 basically means: "use the least amount of space needed to contain the object to be formatted" (avoids unnecessary spaces). Then, after the formatted number, we require the comma plus a space: **", ". This produces our comma-separated values for a row of the matrix (you can use other separators instead of "," if you need). We repeat for every row and that's it.
(The spaces in the format are not really needed, thus one could use format(*(g0,","))
Reference: Metcalf, M., Reid, J., & Cohen, M. (2018). Modern Fortran Explained: Incorporating Fortran 2018. Oxford University Press.

Tens seconds work with a search engine finds me the FLIBS library, which includes a module called csv_file which will write strings, scalars and arrays out is CSV format.

Related

How to save integer array to a file showing numbers as integers

I am attempting to save an array to a txt file, I used the following function:
numpy.savetxt('C:/Users/Adminstrator/Desktop/mesh/ELIST2-clean.txt',array2DClean, delimiter='\t')
The data in file are shown as following:
1.300000000000000000e+01 2.710000000000000000e+02 2.360000000000000000e+02 7.200000000000000000e+01 2.350000000000000000e+02
2.400000000000000000e+01 2.760000000000000000e+02 2.060000000000000000e+02 1.310000000000000000e+02 1.300000000000000000e+02
3.200000000000000000e+01 2.580000000000000000e+02 2.820000000000000000e+02 2.570000000000000000e+02 5.000000000000000000e+01
3.600000000000000000e+01 2.800000000000000000e+02 5.100000000000000000e+01 5.000000000000000000e+01 1.030000000000000000e+02
3.900000000000000000e+01 2.800000000000000000e+02 2.250000000000000000e+02 1.120000000000000000e+02 1.110000000000000000e+02
4.300000000000000000e+01 2.810000000000000000e+02 1.630000000000000000e+02 2.200000000000000000e+01 1.640000000000000000e+02
4.900000000000000000e+01 2.850000000000000000e+02 1.150000000000000000e+02 1.600000000000000000e+02 1.610000000000000000e+02
How can I format the numbers written to the file as whole integers without xe+y notation?
numpy.savetxt has an argument fmt that takes the number format.
fmt: str or sequence of strs, optional
A single format (%10.5f), a sequence of formats, or a multi-format
string, e.g. ‘Iteration %d – %10.5f’, in which case delimiter is
ignored. For complex X, the legal options for fmt are:
a single specifier, fmt=’%.4e’, resulting in numbers formatted like ‘
(%s+%sj)’ % (fmt, fmt)
a full string specifying every real and imaginary part, e.g. ‘ %.4e
%+.4ej %.4e %+.4ej %.4e %+.4ej’ for 3 columns
a list of specifiers, one per column - in this case, the real and
imaginary part must have separate specifiers, e.g. [‘%.3e + %.3ej’,
‘(%.15e%+.15ej)’] for 2 columns
Do numpy.savetxt('C:/Users/Adminstrator/Desktop/mesh/ELIST2-clean.txt',array2DClean, delimiter='\t', fmt='%.0f') to use a format string that writes floats out in fixed-point notation with zero decimal places.
More info here: https://docs.python.org/3/library/string.html#format-specification-mini-language

SPSS string extraction

I have a column with names of different persons separated by comma, for example, (all in 1 cell) Ben Lee, Paul Loy, Boy Lim. I want to separate each name into different columns. How will I do it? (in SPSS syntax).
See this thread with potential solution(s). Namely, credit David Marso and Jon Peck:
* General Parser *.
DATA LIST / X 1-80 (A).
BEGIN DATA 11-0101-423-7384
END DATA.
VECTOR NUMS(10).
COMPUTE #0=0.
LOOP.
COMPUTE #1=INDEX(X,'-').
COMPUTE #0=#0+1.
IF #1>0 NUMS(#0)=NUMBER(SUBSTR(X,1,#1-1),F8).
COMPUTE X=SUBSTR(X,#1+1).
END LOOP IF #1=0.
COMPUTE NUMS(#0)=NUMBER(X,F8).
MATCH FILES FILE * / DROP X.
LIST.
Or alternatively a python solution:
data list free /x(a13).
begin data.
1,13,5,6,99,8
end data.
dataset name data.
begin program.
def split(v):
return v.split(',')
end program.
spssinc trans result = v1 to v6
/formula "split(x)".
do repeat TXTname="Ben Lee" "Paul Loy" "Boy Lim"/VRname=BenLee PaulLoy BoyLim.
compute VRname=index(OriginalColumnName, TXTname)>0.
end repeat.
If there are many more names you might prefer to use standard variable names instead, and add the actual names in the labels instead:
do repeat TXTname="Ben Lee" "Paul Loy" "Boy Lim"/VRname=Name01 to Name03.
compute VRname=index(OriginalColumnName, TXTname)>0.
end repeat.
variable labels
Name01 "Ben Lee"
Name02 "Paul Loy"
Name03 "Boy Lim".

how use struct.pack for list of strings

I want to write a list of strings to a binary file. Suppose I have a list of strings mylist? Assume the items of the list has a '\t' at the end, except the last one has a '\n' at the end (to help me, recover the data back). Example: ['test\t', 'test1\t', 'test2\t', 'testl\n']
For a numpy ndarray, I found the following script that worked (got it from here numpy to r converter):
binfile = open('myfile.bin','wb')
for i in range(mynpdata.shape[1]):
binfile.write(struct.pack('%id' % mynpdata.shape[0], *mynpdata[:,i]))
binfile.close()
Does binfile.write automatically parses all the data if variable has * in front it (such in the *mynpdata[:,i] example above)? Would this work with a list of integers in the same way (e.g. *myIntList)?
How can I do the same with a list of string?
I tried it on a single string using (which I found somewhere on the net):
oneString = 'test'
oneStringByte = bytes(oneString,'utf-8')
struct.pack('I%ds' % (len(oneString),), len(oneString), oneString)
but I couldn't understand why is the % within 'I%ds' above replaced by (len(oneString),) instead of len(oneString) like the ndarray example AND also why is both len(oneString) and oneString passed?
Can someone help me with writing a list of string (if necessary, assuming it is written to the same binary file where I wrote out the ndarray) ?
There's no need for struct. Simply join the strings and encode them using either a specified or an assumed text encoding in order to turn them into bytes.
''.join(L).encode('utf-8')

How can I convert a string into a function in Python?

I have to deal with csv image data from a camera which exports the data with a header. In that header is a simple function for converting CCD counts into power density. This equation includes both the dark offset level as well as a calibration factor. Here is an example from one line of an image file:
Power Density,=,(n - 232) * 4.182e-005 W/cm^2
Notice the commas. The csv header can be expected to have the same structure each time with different constants for dark level (232) and power density conversion (4.182e-005).
What I would like to be able to do is grab the last cell, strip off the units at the end (W/cm^2), and use what is left to define a function in Python. Something like
f = lambda n: '(n - 232) * 4.182e-005'
Is it possible to do so? If so, how?
eval and exec, which use compile, are both ways to dynamically convert code as text to a compiled function. If you dynamically create a new function, you only need to do the conversion once.
row = "Power Density,=,(n - 232) * 4.182e-005 W/cm^2".split(',')
expr = row[2].replace( ' W/cm^2', '')
# f = eval("lambda n:" + expr) # based on your original idea
exec("def f(n): return " + expr) # more flexible
print(f(0))
# -0.00970224
The lambda eval and def exec have the same result, other than f.name, but as usual, the def form is more flexible, even if the flexibility is not needed here.
The usual caveats about executing untrusted code apply. If you are working with photo files not your own and were worried about an adversary feeding you a poisoned file, then indeed you might want to tokenize expr and check that is only has the tokens expected.
I found a way to do it using eval, but I expect that it isn't very pythonic so I would still be interested in seeing other answers.
Here row is the row of interest from a csv.reader object, i.e. the same string I posted in the question divided at the commas.
# Strip the units from the string
strng = row[2].replace( ' W/cm^2', '')
# Define a function based on the string
def f( n):
return eval( strng)
# Evaluate a value
print( f( 0))
# Returns: -0.00970224

store string and integer type CSV file into a matrix matlab

I have a CSV file that has 3 columns having :
String type(This can be a word or a sentence), integer type, integer type [these are the column types]
Now I want to store this data into a matrix,where the string(the whole sentence is stored into one cell)and the integers in one cell each too. I tried this:
fileID=fopen('training.csv');
C=textscan(fileID,'%s %d %d');
But it gives each word of the sentence in a different cell!The whole sentecne should be stored in one cell.How do I do that?
Thank you.
EDIT:It does seem to read anything now,this is what I get
celldisp(C)
C{1}{1} =
jdl
C{2} =
[]
C{3} =
[]
EDIT:
jdl h-yf u ghjktnfhcrjuj hjcljd-yf-ljye 129771 196
EAS CJDTNCRBH YFIRJHNJCNFY UJH HTDL HTCG 819100 458
rcfcyjzcrjuj rfycrf u rhfz edl 547653 677
trfcthbyyehuf h-yt jnltkjv eavc xrfkjdcrjv u hjccbb d 970121 884
H-YF TRFNTHBYYEHUF U EDL XRFKJDCRJUJ 938870 630
jdl yfhyfek h-yf rtktpyjljhjryjuj 525855 598
rhfcyjzhcrf eghfdktybtv dyenhtyybq hfqjyf u ktybycrjuj 709215 403
Pretty much looks like this.It has 3500 rows of data
You could put the strings into quotation marks and then use %q in textscan:
%q String, where double quotation marks indicate text to keep together
EDIT: If you only need to do that once (and not automatically via script in another process), what about manually importing the data from the CSV-File into MATLAB (via the import-tool provided by matlab:
)
and then maybe save the imported variables simply to a MAT-file so you can access it easier in the future!?
If you have Excel, you can use xlsread. You can also try importdata.

Resources