Files
pylib/pylib/data.py

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]