# Path: boris/utilities.py
# def txt2np_array(file_name: str, columns_str: str, substract_first_value: str, converters=None, column_converter=None):
#     """
#     read a txt file (tsv or csv) and return np array with passed columns
# 
#     Args:
#         file_name (str): path of the file to load in numpy array
#         columns_str (str): indexes of columns to be loaded. First columns must be the timestamp. Example: "4,5"
#         substract_first_value (str): "True" or "False"
#         converters (dict): dictionary containing converters
#         column_converter (dict): dictionary key: column index, value: converter name
# 
#     Returns:
#         bool: True if data successfullly loaded, False if case of error
#         str: error message. Empty if success
#         numpy array: data. Empty if not data failed to be loaded
# 
#     """
#     if converters is None:
#         converters = {}
#     if column_converter is None:
#         column_converter = {}
# 
#     # check columns
#     try:
#         columns = [int(x) - 1 for x in columns_str.split(",")]
#     except Exception:
#         return False, f"Problem with columns {columns_str}", np.array([])
# 
#     # check converters
#     np_converters = {}
#     for column_idx in column_converter:
#         if column_converter[column_idx] in converters:
# 
#             conv_name = column_converter[column_idx]
# 
#             function = f"""def {conv_name}(INPUT):\n"""
#             function += """    INPUT = INPUT.decode("utf-8") if isinstance(INPUT, bytes) else INPUT"""
#             for line in converters[conv_name]["code"].split("\n"):
#                 function += f"    {line}\n"
#             function += """    return OUTPUT"""
# 
#             try:
#                 exec(function)
#             except Exception:
#                 return False, f"error in converter: {sys.exc_info()[1]}", np.array([])
# 
#             np_converters[column_idx - 1] = locals()[conv_name]
# 
#         else:
#             return False, f"converter {converters_param[column_idx]} not found", np.array([])
# 
#     # snif txt file
#     try:
#         with open(file_name) as csvfile:
#             buff = csvfile.read(1024)
#             snif = csv.Sniffer()
#             dialect = snif.sniff(buff)
#             has_header = snif.has_header(buff)
#     except Exception:
#         return False, f"{sys.exc_info()[1]}", np.array([])
# 
#     try:
#         data = np.loadtxt(file_name,
#                           delimiter=dialect.delimiter,
#                           usecols=columns,
#                           skiprows=has_header,
#                           converters=np_converters)
#     except Exception:
#         return False, f"{sys.exc_info()[1]}", np.array([])
# 
#     # check if first value must be substracted
#     if substract_first_value == "True":
#         data[:, 0] -= data[:, 0][0]
# 
#     return True, "", data


from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from decimal import Decimal
from boris.utilities import txt2np_array
import sys
import numpy as np
import time
import logging

        self.hlayout1 = QHBoxLayout()
        self.hlayout1.addWidget(QLabel("Zoom"))
        self.hlayout1.addWidget(self.button_plus)
        self.hlayout1.addWidget(self.button_minus)
        self.hlayout1.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))

        self.hlayout2 = QHBoxLayout()
        self.hlayout2.addWidget(QLabel("Value"))
        self.lb_value = QLabel("")
        self.hlayout2.addWidget(self.lb_value)
        self.hlayout2.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))

        self.layout.addLayout(self.hlayout1)
        self.layout.addLayout(self.hlayout2)
        self.layout.addWidget(self.myplot)

        self.setLayout(self.layout)

        self.plot_style = plot_style
        self.plot_title = plot_title
        try:
            self.time_offset = Decimal(time_offset)
        except Exception:
            self.error_msg = "The offset value {} is not a decimal value".format(time_offset)
            return

        self.y_label = y_label
        self.error_msg = ""


# Path: boris/utilities.py
# def txt2np_array(file_name: str, columns_str: str, substract_first_value: str, converters=None, column_converter=None):
#     """
#     read a txt file (tsv or csv) and return np array with passed columns
# 
#     Args:
#         file_name (str): path of the file to load in numpy array
#         columns_str (str): indexes of columns to be loaded. First columns must be the timestamp. Example: "4,5"
#         substract_first_value (str): "True" or "False"
#         converters (dict): dictionary containing converters
#         column_converter (dict): dictionary key: column index, value: converter name
# 
#     Returns:
#         bool: True if data successfullly loaded, False if case of error
#         str: error message. Empty if success
#         numpy array: data. Empty if not data failed to be loaded
# 
#     """
#     if converters is None:
#         converters = {}
#     if column_converter is None:
#         column_converter = {}
# 
#     # check columns
#     try:
#         columns = [int(x) - 1 for x in columns_str.split(",")]
#     except Exception:
#         return False, f"Problem with columns {columns_str}", np.array([])
# 
#     # check converters
#     np_converters = {}
#     for column_idx in column_converter:
#         if column_converter[column_idx] in converters:
# 
#             conv_name = column_converter[column_idx]
# 
#             function = f"""def {conv_name}(INPUT):\n"""
#             function += """    INPUT = INPUT.decode("utf-8") if isinstance(INPUT, bytes) else INPUT"""
#             for line in converters[conv_name]["code"].split("\n"):
#                 function += f"    {line}\n"
#             function += """    return OUTPUT"""
# 
#             try:
#                 exec(function)
#             except Exception:
#                 return False, f"error in converter: {sys.exc_info()[1]}", np.array([])
# 
#             np_converters[column_idx - 1] = locals()[conv_name]
# 
#         else:
#             return False, f"converter {converters_param[column_idx]} not found", np.array([])
# 
#     # snif txt file
#     try:
#         with open(file_name) as csvfile:
#             buff = csvfile.read(1024)
#             snif = csv.Sniffer()
#             dialect = snif.sniff(buff)
#             has_header = snif.has_header(buff)
#     except Exception:
#         return False, f"{sys.exc_info()[1]}", np.array([])
# 
#     try:
#         data = np.loadtxt(file_name,
#                           delimiter=dialect.delimiter,
#                           usecols=columns,
#                           skiprows=has_header,
#                           converters=np_converters)
#     except Exception:
#         return False, f"{sys.exc_info()[1]}", np.array([])
# 
#     # check if first value must be substracted
#     if substract_first_value == "True":
#         data[:, 0] -= data[:, 0][0]
# 
#     return True, "", data


# Path: boris/plot_data_module.py
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from decimal import Decimal
from boris.utilities import txt2np_array
import sys
import numpy as np
import time
import logging


        self.hlayout1 = QHBoxLayout()
        self.hlayout1.addWidget(QLabel("Zoom"))
        self.hlayout1.addWidget(self.button_plus)
        self.hlayout1.addWidget(self.button_minus)
        self.hlayout1.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))

        self.hlayout2 = QHBoxLayout()
        self.hlayout2.addWidget(QLabel("Value"))
        self.lb_value = QLabel("")
        self.hlayout2.addWidget(self.lb_value)
        self.hlayout2.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))

        self.layout.addLayout(self.hlayout1)
        self.layout.addLayout(self.hlayout2)
        self.layout.addWidget(self.myplot)

        self.setLayout(self.layout)

        self.plot_style = plot_style
        self.plot_title = plot_title
        try:
            self.time_offset = Decimal(time_offset)
        except Exception:
            self.error_msg = "The offset value {} is not a decimal value".format(time_offset)
            return

        self.y_label = y_label
        self.error_msg = ""


        result, error_msg, data = txt2np_array(