197 lines
4.9 KiB
Python
197 lines
4.9 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""Read and write data to or from file and manipulate data structures.
|
|
|
|
:Date: 2019-10-11
|
|
|
|
.. module:: data
|
|
:platform: *nix, Windows
|
|
:synopsis: Handle data files and structures.
|
|
|
|
.. moduleauthor:: Daniel Weschke <daniel.weschke@directbox.de>
|
|
"""
|
|
from __future__ import print_function
|
|
import math
|
|
import pickle
|
|
|
|
def read(file_name, x_column, y_column, default=None, verbose=False):
|
|
"""Read ascii data file.
|
|
|
|
:param filename: file to read
|
|
:type filename: str
|
|
:param x_column: column index for the x data (first column is 0)
|
|
:type x_column: int
|
|
:param y_column: column index for the y data (first column is 0)
|
|
:type y_column: int
|
|
:param default: return object if data loading fails
|
|
:type default: object
|
|
:param verbose: verbose information (default = False)
|
|
:type verbose: bool
|
|
|
|
:returns: x and y
|
|
:rtype: tuple(list, list)
|
|
"""
|
|
import re
|
|
|
|
x = default
|
|
y = default
|
|
|
|
if verbose:
|
|
print('check if data is available')
|
|
try:
|
|
file = open(file_name)
|
|
x = []
|
|
y = []
|
|
for row in file:
|
|
fields = re.split(r'\s+', row.strip())
|
|
#print(filds)
|
|
x.append(float(fields[x_column]))
|
|
y.append(float(fields[y_column]))
|
|
file.close()
|
|
except IOError:
|
|
if verbose:
|
|
print('data file not found')
|
|
return x, y
|
|
|
|
def write(file_name, data):
|
|
"""Write ascii file.
|
|
|
|
:param file_name: file to write
|
|
:type file_name: str
|
|
:param data: data to write
|
|
:type data: str
|
|
"""
|
|
with open(file_name, 'w') as file:
|
|
file.write(data)
|
|
|
|
def load(file_name, default=None, verbose=False):
|
|
"""Load stored program objects from binary file.
|
|
|
|
:param file_name: file to load
|
|
:type file_name: str
|
|
:param default: return object if data loading fails
|
|
:type default: object
|
|
:param verbose: verbose information (default = False)
|
|
:type verbose: bool
|
|
|
|
:returns: loaded data
|
|
:rtype: object
|
|
"""
|
|
if verbose:
|
|
print('check if data is available')
|
|
try:
|
|
with open(file_name, 'rb') as input:
|
|
# one load for every dump is needed to load all the data
|
|
object_data = pickle.load(input)
|
|
if verbose:
|
|
print('found:')
|
|
print(object_data)
|
|
except IOError:
|
|
object_data = default
|
|
if verbose:
|
|
print('no saved datas found')
|
|
return object_data
|
|
|
|
def store(file_name, object_data):
|
|
"""Store program objects to binary file.
|
|
|
|
:param file_name: file to store
|
|
:type file_name: str
|
|
:param object_data: data to store
|
|
:type object_data: object
|
|
"""
|
|
with open(file_name, 'wb') as output:
|
|
# every dump needs a load
|
|
pickle.dump(object_data, output, pickle.HIGHEST_PROTOCOL)
|
|
|
|
def fold_list(lst, n):
|
|
"""Convert one-dimensional kx1 array (list) to two-dimensional mxn
|
|
array. m = k / n
|
|
|
|
:param lst: list to convert
|
|
:type lst: list
|
|
:param n: length of the second dimenson
|
|
:type n: int
|
|
|
|
:returns: two-dimensional array (list of lists)
|
|
:rtype: list
|
|
"""
|
|
k = len(lst)
|
|
if k % n == 0:
|
|
length = int(k/n)
|
|
return [lst[i*n:i*n+n] for i in range(length)]
|
|
|
|
def seq(start, stop=None, step=1):
|
|
r"""Create an arithmetic bounded sequence.
|
|
|
|
The sequence is one of the following;
|
|
|
|
- empty :math:`\{\}=\emptyset`, if start and stop are the same
|
|
- degenerate :math:`\{a\}`, if the sequence has only one element.
|
|
- left-close and right-open :math:`[a, b)`
|
|
|
|
:param start: start of the sequence, the lower bound. If only start
|
|
is given than it is interpreted as stop and start will be 0.
|
|
:type start: int or float
|
|
:param stop: stop of sequence, the upper bound.
|
|
:type stop: int or float
|
|
:param step: step size, the common difference (constant difference
|
|
between consecutive terms).
|
|
:type step: int or float
|
|
:returns: arithmetic bounded sequence
|
|
:rtype: list
|
|
"""
|
|
if stop is None:
|
|
return seq(0, start, step)
|
|
|
|
start_str = str(start)
|
|
start_exp = 0
|
|
if '.' in start_str:
|
|
start_exp = len(start_str.split('.')[1])
|
|
|
|
step_str = str(step)
|
|
step_exp = 0
|
|
if '.' in step_str:
|
|
step_exp = len(step_str.split('.')[1])
|
|
|
|
exponent = max(start_exp, step_exp) # no stop because it is an open bound
|
|
|
|
n = int(math.ceil((stop - start)/float(step)))
|
|
#n = int((stop - start)/float(step)) # in py3 math.ceil returns int
|
|
lst = []
|
|
if n > 0:
|
|
lst = [round(start + step*i, exponent) for i in range(n)]
|
|
return lst
|
|
|
|
def unique_ending(ids, n=1):
|
|
"""From id list get list with unique ending.
|
|
|
|
:param ids: ids
|
|
:type ids: list
|
|
:param n: minumum chars or ints
|
|
:type n: int
|
|
|
|
:returns: unique ending of ids
|
|
:rtype: list
|
|
"""
|
|
if ids is not None:
|
|
x = [idi[-n:] for idi in ids]
|
|
if len(x) > len(set(x)):
|
|
return unique_ending(ids, n+1)
|
|
else:
|
|
return x
|
|
|
|
def get_id(ids, uide):
|
|
"""Get full id from unique id ending.
|
|
|
|
:param ids: ids
|
|
:type ids: list
|
|
:param uide: unique id ending
|
|
:type uide: str
|
|
|
|
:returns: full id
|
|
:rtype: str or int
|
|
"""
|
|
# we know it is a unique ending
|
|
return [idi for idi in ids if idi.endswith(uide)][0]
|