"""Module with data writing function definitions
This module includes several functions used in writing data to files in a
well defined way. While you are free to write data to a file in any way you want,
it is preferable to try to keep a lab wide standard by using these methods.
The module was written early on and could probably do with some cleanup... Specifically
old style format strings as well as redundant methods no longer required.
"""
import numpy as np
import os
[docs]def savetxt(myfile, mat, f='%.10e', delim=', ', blocksep='\n'):
"""Write a matrix to a given file
Writes a matrix to a file with a given format specifier and a delimiter. Adds a block
separator at the end. This is very similar to np.savetxt. However, since python3
np.savetxt requires the file to be open in binary write mode.
This function is used internally by both :any:`savedict` and :any:`saveframe`
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
mat : list or np.array
List containing the lines of data to be written as lists (a matrix or list of lists).
f : str, optional
Format specifier for the data (old style).
delim : str, optional
Field delimiter (separation character)
blocksep : str, optional
Characters to write at the end of the matrix. This is generally a single newline to
separate blocks of data.
"""
for line in mat:
line = ['%.10e' % x for x in line]
line = delim.join(line)
myfile.write(line + '\n')
myfile.write(blocksep)
[docs]def savedict(myfile, mydict, f='%.10e', delim=', ', blocksep='\n'):
"""Write a data dictionary to a file as a matrix block
Writes a given dictionary where each element is a list of numbers, i.e., each element in
the dict is though of as a column. Expects all columns to be the same length.
Also, if the file is empty (no writes have been yet performed on it), it will use the
dictionary keys to write the title line.
Internally this function converts the dict to a matrix and uses :py:func:`stlab.utils.writematrix.savetxt` to save
to the file.
The main stlab import renames this function to :code:`stlab.savedict`
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
mydict : dict
Dict containing the data. Each element should be a data column.
f : str, optional
Format specifier for the data (old style).
delim : str, optional
Field delimiter (separation character)
blocksep : str, optional
Characters to write at the end of the matrix. This is generally a single newline to
separate blocks of data.
"""
vv = list(mydict.keys())
writetitle(myfile, vv, delim)
mat = []
for nn in mydict.keys():
mat.append(mydict[nn])
mat = np.asarray(mat)
mat = mat.T
savetxt(myfile, mat, f, delim, blocksep)
[docs]def writeparnames(myfile, params, delim=', '):
"""Writes fit parameter names to file
Intended for writing fit parameter names given a lmfit.Parameters object to a file.
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
params : lmfit.Parameters
Parameters object input from fit
delim : str, optional
Field delimiter (separation character)
"""
myfile.write('#' + delim.join(params.keys()) + '\n')
return
[docs]def writeparams(myfile, params, f='%.10e', delim=', '):
"""Writes fit parameter values to file
Intended for writing fit parameter values given a lmfit.Parameters object to a file.
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
params : lmfit.Parameters
Parameters object input from fit
delim : str, optional
Field delimiter (separation character)
"""
myfile.write(params_to_str(params, f, delim) + '\n')
return
[docs]def params_to_str(params, f='%.10e', delim=', '):
"""Converts fit parameter values to a single line string
Takes a lmfit.Parameters object and converts its parameter values to a single line string.
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
params : lmfit.Parameters
Parameters object input from fit
delim : str, optional
Field delimiter (separation character)
Returns
-------
str
Joined string will all parameters
"""
line = [f % x for x in [params[label].value for label in params.keys()]]
return delim.join(line)
[docs]def savedictarray(myfile, mydictarray, f='%.10e', delim=', ', blocksep='\n'):
"""Writes an array of data dictionaries to a file
Intended for writing a list of dictionaries containing the data columns as elements to a file.
Essentially just repeats :any:`savedict` on every element of the list making sure to include the
title line (derived from the first dictionarly key values) if the file is new.
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
mydictarray : list of dict
List containing the Dicts to be written.
f : str, optional
Format specifier for the data (old style).
delim : str, optional
Field delimiter (separation character)
blocksep : str, optional
Characters to write at the end of the matrix. This is generally a single newline to
separate blocks of data.
"""
vv = list(mydictarray[0].keys())
writetitle(myfile, vv, delim)
for block in mydictarray:
savedict(myfile, block, f, delim, blocksep)
return
# ???
[docs]def writeline(myfile, line, f='.10e', delim=', '):
"""Writes a list of numbers as a single line to a file
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
line : list of float
List containing the numbers to be written
f : str, optional
Format specifier for the data (new style).
delim : str, optional
Field delimiter (separation character)
"""
for x in line[:-1]:
myfile.write("{:{form}}".format(x, form=f) + delim)
myfile.write("{:{form}}\n".format(line[-1], form=f))
myfile.flush()
return
# ???
[docs]def saveframe(myfile, myframe, f='%.10e', delim=', ', blocksep='\n'):
"""Write a pandas Dataframe to a file as a matrix block
Writes a given pandas.DataFrame to a file. Is analogous to :any:`savedict`
Also, if the file is empty (no writes have been yet performed on it), it will use the
dataframe column indexes to write the title line.
Internally this function converts just writes the matrix using :py:func:`stlab.utils.writematrix.savetxt`
The main stlab import renames this function to :code:`stlab.saveframe`
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
mydict : dict
Dict containing the data. Each element should be a data column.
f : str, optional
Format specifier for the data (old style).
delim : str, optional
Field delimiter (separation character)
blocksep : str, optional
Characters to write at the end of the matrix. This is generally a single newline to
separate blocks of data.
"""
vv = list(myframe)
writetitle(myfile, vv, delim)
mat = myframe.values
savetxt(myfile, mat, f, delim, blocksep)
[docs]def saveframearray(myfile, myframearray, f='%.10e', delim=', ',
blocksep='\n'):
"""Writes an array of pandas DataFrame to a file
Analogous to :any:`savedictarray` but using pd.Dataframe instead of dicts. Expects a list of
pd.DataFrames to be written to the file. Also handles writing the title line if the file is
new.
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
mydictarray : list of dict
List containing the Dicts to be written.
f : str, optional
Format specifier for the data (old style).
delim : str, optional
Field delimiter (separation character)
blocksep : str, optional
Characters to write at the end of the matrix. This is generally a single newline to
separate blocks of data.
"""
vv = list(myframearray[0])
writetitle(myfile, vv, delim)
for block in myframearray:
saveframe(myfile, block, f, delim, blocksep)
return
[docs]def writetitle(myfile, vv, delim):
"""Given a list of strings writes the file title line
Does not do anything if the file already has contents. Includes a '#' as first character for
gnuplot. Is used by :any:`savedict` and :any:`saveframe`.
Parameters
----------
myfile : _io.TextIOWrapper
Open file handle for writing
vv : list of str
List of column titles
delim : str, optional
Field delimiter (separation character)
"""
# myfile.flush()
if myfile.tell(
) == 0: # Is the file new? If so, write title line from provided data
varline = '#' + delim.join(vv) + '\n'
myfile.write(varline)