Source code for camiba.data

# This file is part of Camiba.
#
# Camiba is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Camiba is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Camiba. If not, see <http://www.gnu.org/licenses/>.
"""
Here methods for data processing are provided, which mostly serve the purpose
to export data in such a way that it is easy to display in LaTeX using
PGFplots and TikZ.
"""

import numpy as np
import math
import json


[docs]def mat_to_heat(d, x, y, p): """ Convert 2D Array to a heatmap This function takes a 2D ndarray and writes the data to disk such that it can be plotted as a 2D heatmap in pgfplots. Parameters ---------- d : ndarray the array to plot x : ndarray x-axis range y : ndarray y-axis range p : string path to save to """ num_n, num_m = d.shape with open(p, 'w') as o: for nn in range(num_n): for mm in range(num_m): o.write(' '.join('%.16f' % num for num in [y[nn], x[mm], d[nn, mm]])) o.write('\n')
o.write('\n')
[docs]def dict_to_csv(d, p): """ Write a Dictionary to CSV This routine takes a dictionary and uses the keys to use as header for the values writen column wise into a csv file, where we assume that the values are numpy arrays of the same length Parameters ---------- d : dict dictionary of data to write p : string path to write to """ # header list h = [] # first data array f = list(d.items())[0] dtype = np.int for ii, tt in enumerate(list(d.items())): dtype = np.promote_types(dtype, tt[1].dtype) # create an empty array with same datatype as first entry in dictionary v = np.empty( (len(f[1]), len(list(d.items()))), dtype=dtype ) # put everything into a header list and the defined empty array for ii, tt in enumerate(list(d.items())): h.append(tt[0]) v[:, ii] = tt[1] # define the header string header = (',').join(h) with open(p, 'w') as o: o.write(header + '\n') for ii in range(v.shape[0]): o.write(','.join(['%.16f' % num for num in v[ii, :]]))
o.write('\n')
[docs]def csv_to_dict(p): """ Read from CSV to a Dictionary This routine reads in a csv file and returns a dictionary with column headers as keys and columns as numpy arrays. Parameters ---------- p : string path to read from Returns ------- dict the content of the csv as a dictionary of numpy ndarrays """ # first count the rows num_lines = sum(1 for line in open(p, 'r')) # read the dictionary entries arr_keys = [] with open(p, 'r') as f: for ii, ll in enumerate(f): if ii == 0: arr_keys = ll.replace('\n', '').split(',') arr_vals = np.empty( (num_lines - 1, len(arr_keys)) ) else: arr_line = ll.replace('\n', '').split(',') arr_line = list(map(lambda c: float(c), arr_line)) arr_vals[ii-1, :] = arr_line # create the dictionary dct_res = {} for ii, kk in enumerate(arr_keys): dct_res.update({kk: arr_vals[:, ii]})
return dct_res
[docs]class Decoder(json.JSONDecoder): ''' This class can be used to correctly decode integers in json files to Python integers right upon parsing of the json file. >>> json.load('file.json', cls=camiba.data.Decoder) '''
[docs] def decode(self, s): result = super().decode(s)
return self._decode(result) def _decode(self, o): if isinstance(o, str): try: return int(o) except ValueError: return o elif isinstance(o, dict): return {k: self._decode(v) for k, v in o.items()} elif isinstance(o, list): return [self._decode(v) for v in o] else:
return o
[docs]def json_to_tex(in_path, out_path, verbose=False): """ Save Dictionary to TeX Makros This function takes a path to a JSON file and outputs a file of TeX makros to make the values in the JSON file available to TeX. It may be very useful if one would like to run simulations parametrized by an external file and automatically include the used values in tex. If one had a file config.json looking like: >>> { >>> "measurementDataPath": "museData.mat", >>> "measurementDataName": "data", >>> "dictionaryDataPath": "dictData%(d).mat", >>> "dictionaryDataName": "data", >>> "dataShift": [0,0,0], >>> "dataStride": [1,1,1], >>> "recoParams": { >>> "numK": 50 >>> }, >>> "outputPath": "../data/", >>> "logPath": "reconstruct.log" >>> } then issuing >>> json_to_tex(config.json, config.tex) would result in the file config.tex looking like: .. code-block:: none \\newcommand{\\measurementDataPath}{museData.mat} \\newcommand{\\measurementDataName}{data} \\newcommand{\\dictionaryDataName}{data} \\newcommand{\\dataShift1}{0} \\newcommand{\\dataShift2}{0} \\newcommand{\\dataShift3}{0} \\newcommand{\\dataStride1}{1} \\newcommand{\\dataStride2}{1} \\newcommand{\\dataStride3}{1} \\newcommand{\\recoParamsnumK}{50} \\newcommand{\\outputPath}{../data/} \\newcommand{\\logPath}{reconstruct.log} Parameters ---------- in_path : str path to the json file out_path : str path to the tex file that will be created """ json_file = open(in_path) json_dct = json.load(json_file) json_file.close() lstMakros = _dict_to_tex(json_dct, "") out_file = open(out_path, 'w') for mm in lstMakros: if verbose: print(mm) out_file.write(mm)
out_file.close()
[docs]def dict_to_tex(in_dict, out_path, verbose=False): """ Save Dictionary to TeX Makros This function takes a path to a JSON file and outputs a file of TeX makros to make the values in the JSON file available to TeX. It may be very useful if one would like to run simulations parametrized by an external file and automatically include the used values in tex. If one had a dictionary looking like: >>> { >>> "measurementDataPath": "museData.mat", >>> "measurementDataName": "data", >>> "dictionaryDataPath": "dictData%(d).mat", >>> "dictionaryDataName": "data", >>> "dataShift": [0,0,0], >>> "dataStride": [1,1,1], >>> "recoParams": { >>> "numK": 50 >>> }, >>> "outputPath": "../data/", >>> "logPath": "reconstruct.log" >>> } then issuing >>> dict_to_tex(dictionary.json, dictionary.tex) would result in the file config.tex looking like: .. code-block:: none \\newcommand{\\measurementDataPath}{museData.mat} \\newcommand{\\measurementDataName}{data} \\newcommand{\\dictionaryDataName}{data} \\newcommand{\\dataShift1}{0} \\newcommand{\\dataShift2}{0} \\newcommand{\\dataShift3}{0} \\newcommand{\\dataStride1}{1} \\newcommand{\\dataStride2}{1} \\newcommand{\\dataStride3}{1} \\newcommand{\\recoParamsnumK}{50} \\newcommand{\\outputPath}{../data/} \\newcommand{\\logPath}{reconstruct.log} Parameters ---------- in_dict : dict the dictionary to export out_path : str path to the tex file that will be created """ lstMakros = _dict_to_tex(in_dict, "") out_file = open(out_path, 'w') for mm in lstMakros: if verbose: print(mm) out_file.write(mm)
out_file.close() def _dict_to_tex(dct, in_string): res = [] if in_string == "": in_string = '\\newcommand{\\' for kk in dct.keys(): # if we encounter a dictionary, we simply extend the definition of # then corresponding makro if type(dct[kk]) == dict: res.append(*_dict_to_tex(dct[kk], in_string + kk)) elif type(dct[kk]) == list: for ii, ll in enumerate(dct[kk]): res.append( in_string + kk + str(ii + 1) + '}{' + str(ll)+'}' ) else: # leave out anything that contains a %, since we get all sorts # of problems in tex, there if (str(dct[kk])+kk).find("%") == -1: res.append(in_string + kk + '}{' + str(dct[kk])+'}') return res
[docs]def save_params(dct_vars, str_p): """ Save Dictionary of Parameters to Disk This routine allows to store names and their values in a file, which can be read from LaTeX to dynamically update parameter values of simulations in a paper Parameters ---------- dct_vars : dict dictionary of parameter values str_p : string path to save the file to """ # open the file to write with open(str_p, 'w') as f: # write the header f.write("name,value \n") for pp in dct_vars.items(): if type(pp[1]) == float: f.write(pp[0] + "," + "{0:.8f}".format(pp[1])+'\n') else: lg = int(math.ceil(math.log10(pp[1]))) s = "{0:0"+str(lg)+"d}"
f.write(pp[0] + "," + s.format(pp[1])+'\n')