Exemplo n.º 1
0
class MDIChildPlot(PlotWidget):
    LINE_COLORS: List[str] = ['r', 'g', 'b', 'c', 'm', 'y', 'w']
    AXES_NAMES: Dict[int, str] = {2: 'bottom', 3: 'left', 4: 'right'}

    child_number: int = 1

    def __init__(self, **kwargs):
        super(MDIChildPlot, self).__init__(**kwargs)

        self.setAttribute(Qt.WA_DeleteOnClose)

        self.is_untitled: bool = True
        self.is_modified: bool = False

        self.cur_file: str = ''

        self.curves = []

        self.plotItem2 = ViewBox()
        self.plotItem.showAxis('right')
        self.plotItem.scene().addItem(self.plotItem2)
        self.plotItem.getAxis('right').linkToView(self.plotItem2)
        self.plotItem2.setXLink(self.plotItem)
        self.plotItem.showButtons()
        self.plotItem.showGrid(x=True, y=True)

        # Handle view resizing
        def update_views():
            # view has resized; update auxiliary views to match
            self.plotItem2.setGeometry(self.plotItem.vb.sceneBoundingRect())

            # need to re-update linked axes since this was called
            # incorrectly while views had different shapes.
            # (probably this should be handled in ViewBox.resizeEvent)
            self.plotItem2.linkedViewChanged(self.plotItem.vb, self.plotItem2.XAxis)

        update_views()
        self.plotItem.vb.sigResized.connect(update_views)

        # add items to the context menu
        self.plotItem.vb.menu.addSeparator()
        self.delete_curve_menu: QMenu = QMenu('Delete')
        self.copy_curve_menu: QMenu = QMenu('Copy')
        self.paste_curve_menu: QMenu = QMenu('Paste')
        menus = {self.delete_curve_menu:
                 [('Last Curve…', self.delete_last_curve),
                  ('Curves No.…', self.delete_curves),
                  ('All Curves…', self.delete_all_curves)],
                 self.copy_curve_menu:
                 [('Last Curve…', self.copy_last_curve),
                  ('Curves No.…', self.copy_curves),
                  ('All Curves…', self.copy_all_curves)],
                 }
        for parent_menu, actions in menus.items():
            for title, callback in actions:
                new_action: QAction = QAction(title, parent_menu)
                parent_menu.addAction(new_action)
                new_action.triggered.connect(callback)
        self.plotItem.vb.menu.addMenu(self.delete_curve_menu)
        self.plotItem.vb.menu.addMenu(self.copy_curve_menu)
        self.plotItem.vb.menu.addMenu(self.paste_curve_menu)

        # hide buggy menu items
        for undesired_menu_item_index in (5, 2, 1):
            self.plotItem.subMenus.pop(undesired_menu_item_index)
        self.plotItem.subMenus[1].actions()[0].defaultWidget().children()[1].hide()

    def new_file(self):
        self.is_untitled = True
        self.cur_file = f'Plot {MDIChildPlot.child_number:d}'
        MDIChildPlot.child_number += 1
        self.setWindowTitle(self.cur_file + '[*]')
        self.setWindowModified(True)

        # self.sig.connect(self.document_was_modified)

    def load_irtecon_file(self, file_name: str):
        file = QFile(file_name)
        if not file.open(QFile.ReadOnly | QFile.Text):
            QMessageBox.warning(self, 'MDI',
                                f'Cannot read file {file_name}:\n{file.errorString()}.')
            return False

        QApplication.setOverrideCursor(Qt.WaitCursor)
        in_str = QTextStream(file).readAll()
        file_data = IRTECONFile(in_str)
        self.plotItem.setTitle(file_data.sample_name)
        self.plotItem.addLegend()
        for index, curve in enumerate(file_data.curves):
            self.curves.append(self.plotItem.plot(curve.data[..., :2],
                                                  name=curve.legend_key,
                                                  pen=mkPen(self.LINE_COLORS[index % len(self.LINE_COLORS)])))
        for ax in self.AXES_NAMES.values():
            self.plotItem.hideAxis(ax)
        for ax in file_data.axes:
            if ax.axis in self.AXES_NAMES:
                self.plotItem.showAxis(self.AXES_NAMES[ax.axis])
                self.plotItem.setLabel(self.AXES_NAMES[ax.axis], ax.name, ax.unit)
        QApplication.restoreOverrideCursor()

        self.set_current_file(file_name)

        # self.document().contentsChanged.connect(self.document_was_modified)

        return True

    def delete_last_curve(self):
        if not self.curves:
            return
        ret = QMessageBox.warning(self, 'MDI',
                                  'Do you want to delete the last curve?',
                                  QMessageBox.Yes | QMessageBox.No)
        if ret == QMessageBox.Yes:
            self.plotItem.legend.removeItem(self.curves[-1])
            self.curves[-1].clear()
            del self.curves[-1]
            self.is_modified = True
            self.setWindowTitle(self.user_friendly_current_file() + '[*]')
            self.setWindowModified(True)

    def delete_curves(self):
        def parse_range() -> List[int]:
            # https://stackoverflow.com/a/4248689/8554611
            result = set()
            for part in ranges.split(','):
                x = part.split('-')
                result.update(list(range(int(x[0]), int(x[-1]) + 1)))
            return sorted(result)
        if not self.curves:
            return
        ranges, ok = QInputDialog.getText(self, 'Delete Curves', 'Curves No.:')
        if ok:
            for index in reversed(parse_range()):
                index -= 1
                if index in range(len(self.curves)):
                    self.plotItem.legend.removeItem(self.curves[index])
                    self.curves[index].clear()
                    del self.curves[index]
            self.is_modified = True
            self.setWindowTitle(self.user_friendly_current_file() + '[*]')
            self.setWindowModified(True)

    def delete_all_curves(self):
        if not self.curves:
            return
        ret = QMessageBox.question(self, 'MDI',
                                   'Do you want to delete all the curves?',
                                   QMessageBox.Yes | QMessageBox.No)
        if ret == QMessageBox.Yes:
            while self.curves:
                self.plotItem.legend.removeItem(self.curves[-1])
                self.curves[-1].clear()
                del self.curves[-1]
            self.is_modified = True
            self.setWindowTitle(self.user_friendly_current_file() + '[*]')
            self.setWindowModified(True)

    def copy_last_curve(self):
        if not self.curves:
            return
        raise NotImplementedError

    def copy_curves(self, ranges: str):
        def parse_range() -> List[int]:
            # https://stackoverflow.com/a/4248689/8554611
            result = set()
            for part in ranges.split(','):
                x = part.split('-')
                result.update(list(range(int(x[0]), int(x[-1]) + 1)))
            return sorted(result)
        if not self.curves:
            return
        parse_range()
        raise NotImplementedError

    def copy_all_curves(self):
        if not self.curves:
            return
        raise NotImplementedError

    def save(self):
        if self.is_untitled:
            return self.save_as()
        else:
            return self.save_file(self.cur_file)

    def save_as(self):
        file_name, _ = QFileDialog.getSaveFileName(self, 'Save As',
                                                   self.cur_file)
        if not file_name:
            return False

        return self.save_file(file_name)

    def save_file(self, file_name: str):
        file = QFile(file_name)

        if not file.open(QFile.WriteOnly | QFile.Text):
            QMessageBox.warning(self, 'MDI',
                                f'Cannot write file {file_name}:\n{file.errorString()}.')
            return False

        out_str = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        out_str << self.toPlainText()
        QApplication.restoreOverrideCursor()

        self.set_current_file(file_name)
        return True

    def user_friendly_current_file(self):
        def stripped_name(full_file_name):
            return QFileInfo(full_file_name).fileName()

        return stripped_name(self.cur_file)

    def current_file(self):
        return self.cur_file

    def close_event(self, event):
        if self.maybe_save():
            event.accept()
        else:
            event.ignore()

    def maybe_save(self):
        if self.document().isModified():
            ret = QMessageBox.warning(self, 'MDI',
                                      f'"{self.user_friendly_current_file()}" has been modified.\n'
                                      'Do you want to save your changes?',
                                      QMessageBox.Save | QMessageBox.Discard |
                                      QMessageBox.Cancel)
            if ret == QMessageBox.Save:
                return self.save()
            elif ret == QMessageBox.Cancel:
                return False

        return True

    def set_current_file(self, file_name):
        self.cur_file = QFileInfo(file_name).canonicalFilePath()
        self.is_untitled = False
        self.is_modified = False
        self.setWindowModified(False)
        self.setWindowTitle(self.user_friendly_current_file())
    def __init__(self, directory='.', **kwargs):
        super(astraPlotWidget, self).__init__(**kwargs)
        self.beam = raf.beam()
        self.twiss = rtf.twiss()
        self.directory = directory
        ''' twissPlotWidget '''
        self.twissPlotView = GraphicsView(useOpenGL=True)
        self.twissPlotWidget = GraphicsLayout()
        self.twissPlotView.setCentralItem(self.twissPlotWidget)

        self.latticePlotData = imageio.imread('lattice_plot.png')
        self.latticePlots = {}
        self.twissPlots = {}
        i = -1
        for entry in self.twissplotLayout:
            if entry == 'next_row':
                self.twissPlotWidget.nextRow()
            else:
                i += 1
                p = self.twissPlotWidget.addPlot(title=entry['name'])
                p.showGrid(x=True, y=True)
                vb = p.vb
                vb.setYRange(*entry['range'])
                latticePlot = ImageItem(self.latticePlotData)
                latticePlot.setOpts(axisOrder='row-major')
                vb.addItem(latticePlot)
                latticePlot.setZValue(-1)  # make sure this image is on top
                # latticePlot.setOpacity(0.5)
                self.twissPlots[entry['name']] = p.plot(
                    pen=mkPen('b', width=3))
                self.latticePlots[p.vb] = latticePlot
                p.vb.sigRangeChanged.connect(self.scaleLattice)
        ''' beamPlotWidget '''
        self.beamPlotWidget = QWidget()
        self.beamPlotLayout = QVBoxLayout()
        self.item = ImageItem()
        self.beamPlotWidget.setLayout(self.beamPlotLayout)
        self.beamPlotView = ImageView(imageItem=self.item)
        self.rainbow = rainbow()
        self.item.setLookupTable(self.rainbow)
        self.item.setLevels([0, 1])
        # self.beamPlotWidgetGraphicsLayout = GraphicsLayout()
        # p = self.beamPlotWidgetGraphicsLayout.addPlot(title='beam')
        # p.showGrid(x=True, y=True)
        # self.beamPlot = p.plot(pen=None, symbol='+')
        # self.beamPlotView.setCentralItem(self.beamPlotWidgetGraphicsLayout)
        self.beamPlotXAxisCombo = QComboBox()
        self.beamPlotXAxisCombo.addItems(
            ['x', 'y', 'zn', 'cpx', 'cpy', 'BetaGamma'])
        self.beamPlotYAxisCombo = QComboBox()
        self.beamPlotYAxisCombo.addItems(
            ['x', 'y', 'zn', 'cpx', 'cpy', 'BetaGamma'])
        self.beamPlotNumberBins = QSpinBox()
        self.beamPlotNumberBins.setRange(10, 500)
        self.beamPlotNumberBins.setSingleStep(10)
        self.histogramBins = 100
        self.beamPlotNumberBins.setValue(self.histogramBins)
        self.beamPlotAxisWidget = QWidget()
        self.beamPlotAxisLayout = QHBoxLayout()
        self.beamPlotAxisWidget.setLayout(self.beamPlotAxisLayout)
        self.beamPlotAxisLayout.addWidget(self.beamPlotXAxisCombo)
        self.beamPlotAxisLayout.addWidget(self.beamPlotYAxisCombo)
        self.beamPlotAxisLayout.addWidget(self.beamPlotNumberBins)
        self.beamPlotXAxisCombo.currentIndexChanged.connect(self.plotDataBeam)
        self.beamPlotYAxisCombo.currentIndexChanged.connect(self.plotDataBeam)
        self.beamPlotNumberBins.valueChanged.connect(self.plotDataBeam)
        # self.beamPlotXAxisCombo.setCurrentIndex(2)
        # self.beamPlotYAxisCombo.setCurrentIndex(5)
        self.beamPlotLayout.addWidget(self.beamPlotAxisWidget)
        self.beamPlotLayout.addWidget(self.beamPlotView)
        ''' slicePlotWidget '''
        self.sliceParams = [
            {
                'name': 'slice_normalized_horizontal_emittance',
                'units': 'm-rad',
                'text': 'enx'
            },
            {
                'name': 'slice_normalized_vertical_emittance',
                'units': 'm-rad',
                'text': 'eny'
            },
            {
                'name': 'slice_peak_current',
                'units': 'A',
                'text': 'PeakI'
            },
            {
                'name': 'slice_relative_momentum_spread',
                'units': '%',
                'text': 'sigma-p'
            },
        ]
        self.slicePlotWidget = QWidget()
        self.slicePlotLayout = QVBoxLayout()
        self.slicePlotWidget.setLayout(self.slicePlotLayout)
        # self.slicePlotView = GraphicsView(useOpenGL=True)
        self.slicePlotWidgetGraphicsLayout = GraphicsLayoutWidget()
        # self.slicePlots = {}
        self.slicePlotCheckbox = {}
        self.curve = {}
        self.sliceaxis = {}
        self.slicePlotCheckboxWidget = QWidget()
        self.slicePlotCheckboxLayout = QVBoxLayout()
        self.slicePlotCheckboxWidget.setLayout(self.slicePlotCheckboxLayout)
        self.slicePlot = self.slicePlotWidgetGraphicsLayout.addPlot(
            title='Slice', row=0, col=50)
        self.slicePlot.showAxis('left', False)
        self.slicePlot.showGrid(x=True, y=True)
        i = -1
        colors = ['b', 'r', 'g', 'k']
        for param in self.sliceParams:
            i += 1
            axis = AxisItem("left")
            labelStyle = {'color': '#' + colorStr(mkColor(colors[i]))[0:-2]}
            axis.setLabel(text=param['text'],
                          units=param['units'],
                          **labelStyle)
            viewbox = ViewBox()
            axis.linkToView(viewbox)
            viewbox.setXLink(self.slicePlot.vb)
            self.sliceaxis[param['name']] = [axis, viewbox]
            self.curve[param['name']] = PlotDataItem(pen=colors[i], symbol='+')
            viewbox.addItem(self.curve[param['name']])
            col = self.findFirstEmptyColumnInGraphicsLayout()
            self.slicePlotWidgetGraphicsLayout.ci.addItem(axis,
                                                          row=0,
                                                          col=col,
                                                          rowspan=1,
                                                          colspan=1)
            self.slicePlotWidgetGraphicsLayout.ci.addItem(viewbox,
                                                          row=0,
                                                          col=50)
            p.showGrid(x=True, y=True)
            # self.slicePlots[param] = self.slicePlot.plot(pen=colors[i], symbol='+')
            self.slicePlotCheckbox[param['name']] = QCheckBox(param['text'])
            self.slicePlotCheckboxLayout.addWidget(
                self.slicePlotCheckbox[param['name']])
            self.slicePlotCheckbox[param['name']].stateChanged.connect(
                self.plotDataSlice)
        # self.slicePlotView.setCentralItem(self.slicePlotWidgetGraphicsLayout)
        self.slicePlotSliceWidthWidget = QSpinBox()
        self.slicePlotSliceWidthWidget.setMaximum(1000)
        self.slicePlotSliceWidthWidget.setValue(100)
        self.slicePlotSliceWidthWidget.setSingleStep(10)
        self.slicePlotSliceWidthWidget.setSuffix("fs")
        self.slicePlotSliceWidthWidget.setSpecialValueText('Automatic')
        self.slicePlotAxisWidget = QWidget()
        self.slicePlotAxisLayout = QHBoxLayout()
        self.slicePlotAxisWidget.setLayout(self.slicePlotAxisLayout)
        self.slicePlotAxisLayout.addWidget(self.slicePlotCheckboxWidget)
        self.slicePlotAxisLayout.addWidget(self.slicePlotSliceWidthWidget)
        # self.slicePlotXAxisCombo.currentIndexChanged.connect(self.plotDataSlice)
        self.slicePlotSliceWidthWidget.valueChanged.connect(
            self.changeSliceLength)
        # self.beamPlotXAxisCombo.setCurrentIndex(2)
        # self.beamPlotYAxisCombo.setCurrentIndex(5)
        self.slicePlotLayout.addWidget(self.slicePlotAxisWidget)
        self.slicePlotLayout.addWidget(self.slicePlotWidgetGraphicsLayout)

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.tabWidget = QTabWidget()

        self.folderButton = QPushButton('Select Directory')
        self.folderLineEdit = QLineEdit()
        self.folderLineEdit.setReadOnly(True)
        self.folderLineEdit.setText(self.directory)
        self.reloadButton = QPushButton()
        self.reloadButton.setIcon(qApp.style().standardIcon(
            QStyle.SP_BrowserReload))
        self.folderWidget = QGroupBox()
        self.folderLayout = QHBoxLayout()
        self.folderLayout.addWidget(self.folderButton)
        self.folderLayout.addWidget(self.folderLineEdit)
        self.folderLayout.addWidget(self.reloadButton)
        self.folderWidget.setLayout(self.folderLayout)
        self.folderWidget.setMaximumWidth(800)
        self.reloadButton.clicked.connect(
            lambda: self.changeDirectory(self.directory))
        self.folderButton.clicked.connect(self.changeDirectory)

        self.fileSelector = QComboBox()
        self.fileSelector.currentIndexChanged.connect(self.updateScreenCombo)
        self.screenSelector = QComboBox()
        self.screenSelector.currentIndexChanged.connect(self.changeScreen)
        self.beamWidget = QGroupBox()
        self.beamLayout = QHBoxLayout()
        self.beamLayout.addWidget(self.fileSelector)
        self.beamLayout.addWidget(self.screenSelector)
        self.beamWidget.setLayout(self.beamLayout)
        self.beamWidget.setMaximumWidth(800)
        self.beamWidget.setVisible(False)

        self.folderBeamWidget = QWidget()
        self.folderBeamLayout = QHBoxLayout()
        self.folderBeamLayout.setAlignment(Qt.AlignLeft)
        self.folderBeamWidget.setLayout(self.folderBeamLayout)
        self.folderBeamLayout.addWidget(self.folderWidget)
        self.folderBeamLayout.addWidget(self.beamWidget)

        self.tabWidget.addTab(self.twissPlotView, 'Twiss Plots')
        self.tabWidget.addTab(self.beamPlotWidget, 'Beam Plots')
        self.tabWidget.addTab(self.slicePlotWidget, 'Slice Beam Plots')
        self.tabWidget.currentChanged.connect(self.changeTab)
        self.layout.addWidget(self.folderBeamWidget)
        self.layout.addWidget(self.tabWidget)

        self.plotType = 'Twiss'
        self.changeDirectory(self.directory)
Exemplo n.º 3
0
class SiriusTimePlot(PyDMTimePlot):
    """PyDMTimePlot with some extra features."""

    bufferReset = Signal()
    timeSpanChanged = Signal()

    def __init__(self, *args, show_tooltip=False, **kws):
        super().__init__(*args, **kws)
        self._filled_with_arch_data = dict()
        self._show_tooltip = show_tooltip

        self.vb2 = ViewBox()
        self.plotItem.scene().addItem(self.vb2)
        self.vb2.setXLink(self.plotItem)
        self.plotItem.getAxis('right').linkToView(self.vb2)
        self._updateViews()
        self.plotItem.vb.sigResized.connect(self._updateViews)

        self.carch = None

        # show auto adjust button
        self.plotItem.showButtons()

        # use pan mouse mode (3-button)
        self.plotItem.getViewBox().setMouseMode(ViewBox.PanMode)

        # connect sigMouseMoved
        self.plotItem.scene().sigMouseMoved.connect(self._handle_mouse_moved)

        # add new actions to menu
        rst_act = QAction("Clear buffers")
        rst_act.triggered.connect(self._resetBuffers)
        tsp_act = QAction("Change time span")
        tsp_act.triggered.connect(self._changeTimeSpan)
        self.plotItem.scene().contextMenu.extend([rst_act, tsp_act])

    @Property(bool)
    def showToolTip(self):
        """
        Whether to show or not tooltip with curve values.

        Returns
        -------
        use : bool
            Tooltip enable status in use
        """
        return self._show_tooltip

    @showToolTip.setter
    def showToolTip(self, new_show):
        """
        Whether to show or not tooltip with curve values.

        Parameters
        ----------
        new_show : bool
            The new tooltip enable status to use
        """
        self._show_tooltip = new_show

    def addCurve(self, plot_item, axis='left', curve_color=None):
        """Reimplement to use right axis."""
        if curve_color is None:
            curve_color = utilities.colors.default_colors[len(
                self._curves) % len(utilities.colors.default_colors)]
            plot_item.color_string = curve_color
        self._curves.append(plot_item)
        if axis == 'left':
            self.plotItem.addItem(plot_item)
        elif axis == 'right':
            if not self.plotItem.getAxis('right').isVisible():
                self.plotItem.showAxis('right')
            self.vb2.addItem(plot_item)
        else:
            raise ValueError('Choose a valid axis!')

        # Connect channels
        for chan in plot_item.channels():
            if chan:
                chan.connect()

    def addYChannel(self,
                    y_channel=None,
                    name=None,
                    color=None,
                    lineStyle=None,
                    lineWidth=None,
                    symbol=None,
                    symbolSize=None,
                    axis='left'):
        """Reimplement to use SiriusTimePlotItem and right axis."""
        plot_opts = dict()
        plot_opts['symbol'] = symbol
        if symbolSize is not None:
            plot_opts['symbolSize'] = symbolSize
        if lineStyle is not None:
            plot_opts['lineStyle'] = lineStyle
        if lineWidth is not None:
            plot_opts['lineWidth'] = lineWidth

        # Add curve
        new_curve = SiriusTimePlotItem(
            self,
            y_channel,
            plot_by_timestamps=self._plot_by_timestamps,
            name=name,
            color=color,
            **plot_opts)
        new_curve.setUpdatesAsynchronously(self.updatesAsynchronously)
        new_curve.setBufferSize(self._bufferSize, initialize_buffer=True)

        self.update_timer.timeout.connect(new_curve.asyncUpdate)
        self.addCurve(new_curve, axis, curve_color=color)

        new_curve.data_changed.connect(self.set_needs_redraw)
        self.redraw_timer.start()

        return new_curve

    def updateXAxis(self, update_immediately=False):
        """Reimplement to show only existing range."""
        if len(self._curves) == 0:
            return

        if self._plot_by_timestamps:
            if self._update_mode == PyDMTimePlot.SynchronousMode:
                maxrange = max([curve.max_x() for curve in self._curves])
            else:
                maxrange = time.time()

            mini = Time.now().timestamp()
            for curve in self._curves:
                firstvalid = (curve.data_buffer[0] != 0).argmax()
                if curve.data_buffer[0, firstvalid] == 0:
                    continue
                mini = min(mini, curve.data_buffer[0, firstvalid])
            minrange = max(maxrange - self._time_span, mini)

            self.plotItem.setXRange(minrange,
                                    maxrange,
                                    padding=0.0,
                                    update=update_immediately)
        else:
            diff_time = self.starting_epoch_time - \
                max([curve.max_x() for curve in self._curves])
            if diff_time > DEFAULT_X_MIN:
                diff_time = DEFAULT_X_MIN
            self.getViewBox().setLimits(minXRange=diff_time)

    def _updateViews(self):
        self.vb2.setGeometry(self.plotItem.vb.sceneBoundingRect())
        self.vb2.linkedViewChanged(self.plotItem.vb, self.vb2.XAxis)

    def _get_value_from_arch(self, pvname, t_init, t_end, process_type,
                             process_bin_intvl):
        """Get values from archiver."""
        if self.carch is None:
            self.carch = ClientArchiver()
        self.carch.timeout = 120
        data = self.carch.getData(pvname, t_init, t_end, process_type,
                                  process_bin_intvl)
        if not data:
            return
        return data['timestamp'], data['value']

    def fill_curve_with_archdata(self,
                                 curve,
                                 pvname,
                                 t_init,
                                 t_end,
                                 factor=None,
                                 process_type='',
                                 process_bin_intvl=None):
        """Fill curve with archiver data."""
        data = self._get_value_from_arch(pvname, t_init, t_end, process_type,
                                         process_bin_intvl)
        if not data:
            return
        datax, datay = data
        self.fill_curve_buffer(curve, datax, datay, factor)

        self._filled_with_arch_data[pvname] = dict(
            curve=curve,
            factor=factor,
            process_type=process_type,
            process_bin_intvl=process_bin_intvl)

    def fill_curve_buffer(self, curve, datax, datay, factor=None):
        """Fill curve buffer."""
        nrpts = len(datax)
        if not nrpts:
            return
        buff = _np.zeros((2, self.bufferSize), order='f', dtype=float)
        if nrpts > self.bufferSize:
            smpls2discard = nrpts - self.bufferSize
            datax = datax[smpls2discard:]
            datay = datay[smpls2discard:]
            nrpts = len(datax)
        firstsmpl2fill = self.bufferSize - nrpts
        buff[0, firstsmpl2fill:] = datax
        buff[1, firstsmpl2fill:] = datay
        if factor:
            buff[1, :] /= factor
        curve.data_buffer = buff
        curve.points_accumulated = nrpts
        curve._min_y_value = min(datay)
        curve._max_y_value = max(datay)
        curve.latest_value = datay[-1]

    def _resetBuffers(self):
        for curve in self._curves:
            curve.initialize_buffer()
        self.bufferReset.emit()

    def _changeTimeSpan(self):
        new_time_span, ok = QInputDialog.getInt(
            self, 'Input', 'Set new time span value [s]: ')
        if not ok:
            return

        if new_time_span > self.timeSpan:
            t_end = Time.now()
            t_init = t_end - new_time_span
            for pvname, info in self._filled_with_arch_data.items():
                self.fill_curve_with_archdata(info['curve'], pvname,
                                              t_init.get_iso8601(),
                                              t_end.get_iso8601(),
                                              info['factor'],
                                              info['process_type'],
                                              info['process_bin_intvl'])

        self.timeSpan = new_time_span
        self.timeSpanChanged.emit()

    def _handle_mouse_moved(self, pos):
        """Show tooltip at mouse move."""
        if not self._show_tooltip:
            return

        # create label tooltip, if needed
        if not hasattr(self, 'label_tooltip'):
            self.label_tooltip = QLabel(self, Qt.ToolTip)
            self.timer_tooltip = QTimer(self)
            self.timer_tooltip.timeout.connect(self.label_tooltip.hide)
            self.timer_tooltip.setInterval(1000)

        # find nearest curve point
        nearest = (self._curves[0], _np.inf, None, None)
        for idx, curve in enumerate(self._curves):
            if not curve.isVisible():
                continue
            mappos = curve.mapFromScene(pos)
            posx, posy = mappos.x(), mappos.y()
            xData, yData = curve.curve.xData, curve.curve.yData
            if not xData.size:
                continue
            diffx = xData - posx
            idx = _np.argmin(_np.abs(diffx))
            if diffx[idx] < 0.5:
                valx, valy = xData[idx], yData[idx]
                diffy = abs(valy - posy)
                if diffy < nearest[1]:
                    nearest = (curve, diffy, valx, valy)

        # show tooltip
        curve, diffy, valx, valy = nearest
        ylimts = self.getViewBox().state['viewRange'][1]
        ydelta = ylimts[1] - ylimts[0]
        if diffy < 1e-2 * ydelta:
            txt = Time(timestamp=valx).get_iso8601() + '\n'
            txt += f'{curve.name()}: {valy:.3f}'
            font = QApplication.instance().font()
            font.setPointSize(font.pointSize() - 10)
            palette = QPalette()
            palette.setColor(QPalette.WindowText, curve.color)
            self.label_tooltip.setText(txt)
            self.label_tooltip.setFont(font)
            self.label_tooltip.setPalette(palette)
            self.label_tooltip.move(self.mapToGlobal(pos.toPoint()))
            self.label_tooltip.show()
            self.timer_tooltip.start()
            curve.scatter.setData(pos=[
                (valx, valy),
            ],
                                  symbol='o',
                                  size=15,
                                  brush=mkBrush(curve.color))
            curve.scatter.show()
    def __init__(self, directory='.', **kwargs):
        super(astraPlotWidget, self).__init__(**kwargs)
        self.beam = raf.beam()
        self.twiss = rtf.twiss()
        self.directory = directory
        ''' twissPlotWidget '''
        self.twissPlotView = GraphicsView(useOpenGL=True)
        self.twissPlotWidget = GraphicsLayout()
        self.twissPlotView.setCentralItem(self.twissPlotWidget)

        self.latticePlotData = imageio.imread(
            os.path.dirname(os.path.abspath(__file__)) + '/lattice_plot.png')
        self.latticePlots = {}
        self.twissPlots = {}
        i = -1
        for entry in self.twissplotLayout:
            if entry == 'next_row':
                self.twissPlotWidget.nextRow()
            else:
                i += 1
                p = self.twissPlotWidget.addPlot(title=entry['name'])
                p.showGrid(x=True, y=True)
                vb = p.vb
                vb.setYRange(*entry['range'])
                latticePlot = ImageItem(self.latticePlotData)
                latticePlot.setOpts(axisOrder='row-major')
                vb.addItem(latticePlot)
                latticePlot.setZValue(-1)  # make sure this image is on top
                # latticePlot.setOpacity(0.5)
                self.twissPlots[entry['name']] = p.plot(
                    pen=mkPen('b', width=3))
                self.latticePlots[p.vb] = latticePlot
                p.vb.sigRangeChanged.connect(self.scaleLattice)
        ''' beamPlotWidget '''
        self.beamPlotWidget = QWidget()
        self.beamPlotLayout = QVBoxLayout()
        self.beamPlotWidget.setLayout(self.beamPlotLayout)

        #
        # self.beamPlotChoice =
        #

        self.beamPlotAxisWidget = QWidget()
        self.beamPlotAxisWidget.setMaximumHeight(100)
        Form = self.beamPlotAxisWidget

        self.beamPlotXAxisDict = OrderedDict()
        self.beamPlotXAxisDict['x'] = {'scale': 1e3, 'axis': 'x [mm]'}
        self.beamPlotXAxisDict['y'] = {'scale': 1e3, 'axis': 'y [mm]'}
        self.beamPlotXAxisDict['z'] = {
            'scale': 1e6,
            'axis': 'z [micron]',
            'norm': True
        }
        self.beamPlotXAxisDict['t'] = {
            'scale': 1e12,
            'axis': 't [ps]',
            'norm': True
        }
        self.beamPlotXAxisDict['cpx'] = {'scale': 1e3, 'axis': 'cpx [keV]'}
        self.beamPlotXAxisDict['cpy'] = {'scale': 1e3, 'axis': 'cpy [keV]'}
        self.beamPlotXAxisDict['BetaGamma'] = {
            'scale': 0.511,
            'axis': 'cp [MeV]'
        }

        # Form.setObjectName(("Form"))
        # Form.resize(874, 212)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth())
        Form.setSizePolicy(sizePolicy)
        self.horizontalLayout = QHBoxLayout(Form)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.beamPlotXAxisCombo = QComboBox(Form)
        self.beamPlotXAxisCombo.addItems(list(self.beamPlotXAxisDict.keys()))
        self.beamPlotXAxisCombo.setCurrentIndex(2)
        self.horizontalLayout.addWidget(self.beamPlotXAxisCombo)
        self.beamPlotYAxisCombo = QComboBox(Form)
        self.beamPlotYAxisCombo.addItems(list(self.beamPlotXAxisDict.keys()))
        self.beamPlotYAxisCombo.setCurrentIndex(6)
        self.horizontalLayout.addWidget(self.beamPlotYAxisCombo)
        self.groupBox = QGroupBox(Form)
        self.groupBox.setObjectName("groupBox")
        self.formLayout = QFormLayout(self.groupBox)
        self.formLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        self.formLayout.setObjectName("formLayout")
        self.chooseSliceWidth = QRadioButton(self.groupBox)
        self.chooseSliceWidth.setObjectName(("chooseSliceWidth"))
        self.formLayout.setWidget(0, QFormLayout.LabelRole,
                                  self.chooseSliceWidth)
        self.sliceWidth = QDoubleSpinBox(self.groupBox)
        self.sliceWidth.setDecimals(6)
        self.sliceWidth.setObjectName("sliceWidth")
        self.formLayout.setWidget(0, QFormLayout.FieldRole, self.sliceWidth)
        self.chooseSliceNumber = QRadioButton(self.groupBox)
        self.chooseSliceNumber.setChecked(True)
        self.chooseSliceNumber.setObjectName("chooseSliceNumber")
        self.formLayout.setWidget(1, QFormLayout.LabelRole,
                                  self.chooseSliceNumber)
        self.sliceNumber = QSpinBox(self.groupBox)
        self.sliceNumber.setObjectName(("sliceNumber"))
        self.formLayout.setWidget(1, QFormLayout.FieldRole, self.sliceNumber)
        self.horizontalLayout.addWidget(self.groupBox)
        self.chooseSliceWidth.setText(_translate("Form", "Slice Width", None))
        self.chooseSliceNumber.setText(
            _translate("Form", "Number of Slices", None))
        self.sliceWidth.setRange(1e-6, 1)
        self.sliceWidth.setSingleStep(0.00001)
        self.histogramWidth = 0.0005
        self.sliceWidth.setValue(self.histogramWidth)
        # self.sliceNumber = QSpinBox()
        self.sliceNumber.setRange(10, 10000)
        self.sliceNumber.setSingleStep(10)
        self.histogramBins = 100
        self.sliceNumber.setValue(self.histogramBins)

        # self.beamPlotXAxisCombo = QComboBox()

        # self.beamPlotAxisLayout = QHBoxLayout()
        # self.beamPlotAxisWidget.setLayout(self.beamPlotAxisLayout)

        # self.beamPlotAxisLayout.addWidget(self.beamPlotXAxisCombo)
        # self.beamPlotAxisLayout.addWidget(self.beamPlotYAxisCombo)
        # self.beamPlotAxisLayout.addWidget(self.beamPlotNumberBins)
        self.beamPlotXAxisCombo.currentIndexChanged.connect(self.plotDataBeam)
        self.beamPlotYAxisCombo.currentIndexChanged.connect(self.plotDataBeam)
        self.chooseSliceNumber.toggled.connect(self.plotDataBeam)
        self.sliceNumber.valueChanged.connect(self.plotDataBeam)
        self.sliceWidth.valueChanged.connect(self.plotDataBeam)
        # self.beamPlotXAxisCombo.setCurrentIndex(2)
        # self.beamPlotYAxisCombo.setCurrentIndex(5)
        self.canvasWidget = QWidget()
        l = QVBoxLayout(self.canvasWidget)
        self.sc = MyStaticMplCanvas(self.canvasWidget,
                                    width=1,
                                    height=1,
                                    dpi=150)
        l.addWidget(self.sc)
        self.beamPlotLayout.addWidget(self.beamPlotAxisWidget)
        self.beamPlotLayout.addWidget(self.canvasWidget)
        ''' slicePlotWidget '''
        self.sliceParams = [
            {
                'name': 'slice_normalized_horizontal_emittance',
                'units': 'm-rad',
                'text': 'enx'
            },
            {
                'name': 'slice_normalized_vertical_emittance',
                'units': 'm-rad',
                'text': 'eny'
            },
            {
                'name': 'slice_peak_current',
                'units': 'A',
                'text': 'PeakI'
            },
            {
                'name': 'slice_relative_momentum_spread',
                'units': '%',
                'text': 'sigma-p'
            },
            {
                'name': 'slice_beta_x',
                'units': 'm',
                'text': 'beta_x'
            },
            {
                'name': 'slice_beta_y',
                'units': 'm',
                'text': 'beta_y'
            },
        ]
        self.slicePlotWidget = QWidget()
        self.slicePlotLayout = QVBoxLayout()
        self.slicePlotWidget.setLayout(self.slicePlotLayout)
        # self.slicePlotView = GraphicsView(useOpenGL=True)
        self.slicePlotWidgetGraphicsLayout = GraphicsLayoutWidget()
        # self.slicePlots = {}
        self.slicePlotCheckbox = {}
        self.curve = {}
        self.sliceaxis = {}
        self.slicePlotCheckboxWidget = QWidget()
        self.slicePlotCheckboxLayout = QVBoxLayout()
        self.slicePlotCheckboxWidget.setLayout(self.slicePlotCheckboxLayout)
        self.slicePlot = self.slicePlotWidgetGraphicsLayout.addPlot(
            title='Slice', row=0, col=50)
        self.slicePlot.showAxis('left', False)
        self.slicePlot.showGrid(x=True, y=True)
        i = -1
        colors = ['b', 'r', 'g', 'k', 'y', 'm', 'c']
        for param in self.sliceParams:
            i += 1
            axis = AxisItem("left")
            labelStyle = {'color': '#' + colorStr(mkColor(colors[i]))[0:-2]}
            axis.setLabel(text=param['text'],
                          units=param['units'],
                          **labelStyle)
            viewbox = ViewBox()
            axis.linkToView(viewbox)
            viewbox.setXLink(self.slicePlot.vb)
            self.sliceaxis[param['name']] = [axis, viewbox]
            self.curve[param['name']] = PlotDataItem(pen=colors[i], symbol='+')
            viewbox.addItem(self.curve[param['name']])
            col = self.findFirstEmptyColumnInGraphicsLayout()
            self.slicePlotWidgetGraphicsLayout.ci.addItem(axis,
                                                          row=0,
                                                          col=col,
                                                          rowspan=1,
                                                          colspan=1)
            self.slicePlotWidgetGraphicsLayout.ci.addItem(viewbox,
                                                          row=0,
                                                          col=50)
            p.showGrid(x=True, y=True)
            # self.slicePlots[param] = self.slicePlot.plot(pen=colors[i], symbol='+')
            self.slicePlotCheckbox[param['name']] = QCheckBox(param['text'])
            self.slicePlotCheckboxLayout.addWidget(
                self.slicePlotCheckbox[param['name']])
            self.slicePlotCheckbox[param['name']].stateChanged.connect(
                self.plotDataSlice)
        # self.slicePlotView.setCentralItem(self.slicePlotWidgetGraphicsLayout)
        self.slicePlotSliceWidthWidget = QSpinBox()
        self.slicePlotSliceWidthWidget.setMaximum(500)
        self.slicePlotSliceWidthWidget.setValue(100)
        self.slicePlotSliceWidthWidget.setSingleStep(10)
        self.slicePlotSliceWidthWidget.setSuffix(" slices")
        self.slicePlotSliceWidthWidget.setSpecialValueText('Automatic')
        self.slicePlotAxisWidget = QWidget()
        self.slicePlotAxisLayout = QHBoxLayout()
        self.slicePlotAxisWidget.setLayout(self.slicePlotAxisLayout)
        self.slicePlotAxisLayout.addWidget(self.slicePlotCheckboxWidget)
        self.slicePlotAxisLayout.addWidget(self.slicePlotSliceWidthWidget)
        # self.slicePlotXAxisCombo.currentIndexChanged.connect(self.plotDataSlice)
        self.slicePlotSliceWidthWidget.valueChanged.connect(
            self.changeSliceLength)
        # self.beamPlotXAxisCombo.setCurrentIndex(2)
        # self.beamPlotYAxisCombo.setCurrentIndex(5)
        self.slicePlotLayout.addWidget(self.slicePlotAxisWidget)
        self.slicePlotLayout.addWidget(self.slicePlotWidgetGraphicsLayout)

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.tabWidget = QTabWidget()

        self.folderButton = QPushButton('Select Directory')
        self.folderLineEdit = QLineEdit()
        self.folderLineEdit.setReadOnly(True)
        self.folderLineEdit.setText(self.directory)
        self.reloadButton = QPushButton()
        self.reloadButton.setIcon(qApp.style().standardIcon(
            QStyle.SP_BrowserReload))
        self.folderWidget = QGroupBox()
        self.folderLayout = QHBoxLayout()
        self.folderLayout.addWidget(self.folderButton)
        self.folderLayout.addWidget(self.folderLineEdit)
        self.folderLayout.addWidget(self.reloadButton)
        self.folderWidget.setLayout(self.folderLayout)
        self.folderWidget.setMaximumWidth(800)
        self.reloadButton.clicked.connect(
            lambda: self.changeDirectory(self.directory))
        self.folderButton.clicked.connect(self.changeDirectory)

        self.fileSelector = QComboBox()
        self.fileSelector.currentIndexChanged.connect(self.updateScreenCombo)
        self.screenSelector = QComboBox()
        self.screenSelector.currentIndexChanged.connect(self.changeScreen)
        self.beamWidget = QGroupBox()
        self.beamLayout = QHBoxLayout()
        self.beamLayout.addWidget(self.fileSelector)
        self.beamLayout.addWidget(self.screenSelector)
        self.beamWidget.setLayout(self.beamLayout)
        self.beamWidget.setMaximumWidth(800)
        self.beamWidget.setVisible(False)

        self.folderBeamWidget = QWidget()
        self.folderBeamLayout = QHBoxLayout()
        self.folderBeamLayout.setAlignment(Qt.AlignLeft)
        self.folderBeamWidget.setLayout(self.folderBeamLayout)
        self.folderBeamLayout.addWidget(self.folderWidget)
        self.folderBeamLayout.addWidget(self.beamWidget)

        self.tabWidget.addTab(self.twissPlotView, 'Twiss Plots')
        self.tabWidget.addTab(self.beamPlotWidget, 'Beam Plots')
        self.tabWidget.addTab(self.slicePlotWidget, 'Slice Beam Plots')
        # self.log = lw.loggerWidget()
        # self.log.addLogger(logger)
        # sys.stdout = lw.redirectLogger(self.log, 'stdout')
        # self.tabWidget.addTab(self.log,'Log')
        self.tabWidget.currentChanged.connect(self.changeTab)
        self.layout.addWidget(self.folderBeamWidget)
        self.layout.addWidget(self.tabWidget)

        self.plotType = 'Twiss'
        self.changeDirectory(self.directory)
class DataWidget(QWidget):
    def __init__(self, parent, shared_data):
        super(DataWidget, self).__init__(parent)
        self.__shared_data = shared_data
        self.__shared_data.update_sync.emit()

        # Add the file selection controls
        self.__dir_picker_button = QPushButton()
        self.__dir_picker_button.setEnabled(True)
        self.__dir_picker_button.setText("Load data")
        self.__dir_picker_button.setIcon(self.style().standardIcon(QStyle.SP_DirIcon))
        self.__dir_picker_button.setToolTip('Select the directory using the file explorer')
        self.__dir_picker_button.clicked.connect(self.__open_dir_picker)

        # Add the sync controls
        self.__sync_time_label = QLabel()
        self.__sync_time_label.setText('Enter the timecode (HH:mm:ss:zzz) : ')

        self.__sync_time_edit = QTimeEdit()
        self.__sync_time_edit.setDisplayFormat('HH:mm:ss:zzz')
        self.__sync_time_edit.setEnabled(False)

        self.__sync_time_button = QPushButton()
        self.__sync_time_button.setText('Sync data')
        self.__sync_time_button.setEnabled(False)
        self.__sync_time_button.clicked.connect(self.__sync_data)

        # Create the layout for the file controls
        dir_layout = QHBoxLayout()
        dir_layout.setContentsMargins(0, 0, 0, 0)
        dir_layout.addWidget(self.__dir_picker_button)
        dir_layout.addStretch(1)
        dir_layout.addWidget(self.__sync_time_label)
        dir_layout.addWidget(self.__sync_time_edit)
        dir_layout.addWidget(self.__sync_time_button)

        # Create the axis and their viewbox
        self.__x_axis_item = AxisItem('left')
        self.__y_axis_item = AxisItem('left')
        self.__z_axis_item = AxisItem('left')

        self.__x_axis_viewbox = ViewBox()
        self.__y_axis_viewbox = ViewBox()
        self.__z_axis_viewbox = ViewBox()

        # Create the widget which will display the data
        self.__graphic_view = GraphicsView(background="#ecf0f1")
        self.__graphic_layout = GraphicsLayout()
        self.__graphic_view.setCentralWidget(self.__graphic_layout)

        # Add the axis to the widget
        self.__graphic_layout.addItem(self.__x_axis_item, row=2, col=3, rowspan=1, colspan=1)
        self.__graphic_layout.addItem(self.__y_axis_item, row=2, col=2, rowspan=1, colspan=1)
        self.__graphic_layout.addItem(self.__z_axis_item, row=2, col=1, rowspan=1, colspan=1)

        self.__plot_item = PlotItem()
        self.__plot_item_viewbox = self.__plot_item.vb
        self.__graphic_layout.addItem(self.__plot_item, row=2, col=4, rowspan=1, colspan=1)

        self.__graphic_layout.scene().addItem(self.__x_axis_viewbox)
        self.__graphic_layout.scene().addItem(self.__y_axis_viewbox)
        self.__graphic_layout.scene().addItem(self.__z_axis_viewbox)

        self.__x_axis_item.linkToView(self.__x_axis_viewbox)
        self.__y_axis_item.linkToView(self.__y_axis_viewbox)
        self.__z_axis_item.linkToView(self.__z_axis_viewbox)

        self.__x_axis_viewbox.setXLink(self.__plot_item_viewbox)
        self.__y_axis_viewbox.setXLink(self.__plot_item_viewbox)
        self.__z_axis_viewbox.setXLink(self.__plot_item_viewbox)

        self.__plot_item_viewbox.sigResized.connect(self.__update_views)
        self.__x_axis_viewbox.enableAutoRange(axis=ViewBox.XAxis, enable=True)
        self.__y_axis_viewbox.enableAutoRange(axis=ViewBox.XAxis, enable=True)
        self.__z_axis_viewbox.enableAutoRange(axis=ViewBox.XAxis, enable=True)

        # Create the final layout
        self.__v_box = QVBoxLayout()
        self.__v_box.addLayout(dir_layout)
        self.__v_box.addWidget(self.__graphic_view)

        self.setLayout(self.__v_box)

        self.__restore_state()

    def __open_dir_picker(self):
        self.__shared_data.data_file_path = QFileDialog.getOpenFileUrl(self, 'Open the Hexoskin data directory',
                                                                       QDir.homePath())[0]
        if self.__shared_data.data_file_path is not None:
            try:
                self.__load_data()
                self.__add_selector_acc_gyr()
                self.__show_data('ACC_X', 'ACC_Y', 'ACC_Z')
            except FileNotFoundError:
                pass
            except UnicodeDecodeError:
                pass

    def __load_data(self):
        if self.__shared_data.data_file_path is not None:
            self.__shared_data.import_parameter()

    def __show_data(self, field1, field2, field3):
        if self.__shared_data.parameter is not None:
            # Generate the timecodes if needed
            if len(self.__shared_data.parameter['TIMECODE']) == 0:
                if self.__shared_data.sampling_rate is None:
                    result = False
                    while not result and result == 0:
                        result = self.__show_sampling_rate_picker()

                self.__shared_data.add_timecode()

            self.__x_axis_viewbox.clear()
            self.__y_axis_viewbox.clear()
            self.__z_axis_viewbox.clear()

            # Show the 3 selected fields
            self.__x_axis_viewbox.addItem(PlotCurveItem(list(map(int, self.__shared_data.parameter.get(field1))),
                                                        pen='#34495e'))
            self.__y_axis_viewbox.addItem(PlotCurveItem(list(map(int, self.__shared_data.parameter.get(field2))),
                                                        pen='#9b59b6'))
            self.__z_axis_viewbox.addItem(PlotCurveItem(list(map(int, self.__shared_data.parameter.get(field3))),
                                                        pen='#3498db'))

            self.__x_axis_item.setLabel(field1, color="#34495e")
            self.__y_axis_item.setLabel(field2, color="#9b59b6")
            self.__z_axis_item.setLabel(field3, color="#3498db")

            # Add the middle line and the bottom timecodes
            timecodes = self.__shared_data.parameter['TIMECODE']
            middle = [0] * len(timecodes)
            self.__plot_item_viewbox.addItem(PlotCurveItem(middle, pen='#000000'))
            self.__plot_item.getAxis('bottom').setTicks(
                self.__generate_time_ticks(timecodes, self.__shared_data.sampling_rate))

            # Enable the controls
            self.__sync_time_edit.setEnabled(True)
            self.__sync_time_button.setEnabled(True)
            self.__dir_picker_button.setEnabled(False)
        self.__update_views()

    def __update_views(self):
        self.__x_axis_viewbox.setGeometry(self.__plot_item_viewbox.sceneBoundingRect())
        self.__y_axis_viewbox.setGeometry(self.__plot_item_viewbox.sceneBoundingRect())
        self.__z_axis_viewbox.setGeometry(self.__plot_item_viewbox.sceneBoundingRect())

    def __generate_time_ticks(self, timecodes, rate):
        ticks = list()

        steps = [rate * 30, rate * 15, rate * 5, rate]
        for step in steps:
            temp = list()
            i = step
            while i in range(len(timecodes)):
                temp.append((i, timecodes[i].strftime('%H:%M:%S:') + str(int(timecodes[i].microsecond / 1000))))
                i += step
            ticks.append(temp)

        return ticks

    def __sync_data(self):
        self.__shared_data.data_sync = self.__sync_time_edit.text()
        self.__shared_data.update_sync.emit()

    def __show_sampling_rate_picker(self) -> bool:
        self.__shared_data.sampling_rate, result = QInputDialog.getInt(self, 'Set sampling rate value', 'Sampling rate')
        return result

    def __add_selector_acc_gyr(self):
        if 'GYR_X' in self.__shared_data.parameter.keys() or 'GYR_Y' in self.__shared_data.parameter.keys() \
                or 'GYR_Z' in self.__shared_data.parameter.keys():
            show_acc = QPushButton()
            show_acc.setText('Show Accelerometer Axis')
            show_acc.clicked.connect(self.__show_acc)

            show_gyr = QPushButton()
            show_gyr.setText('Show Gyroscope Axis')
            show_gyr.clicked.connect(self.__show_gyr)

            layout = QHBoxLayout()
            layout.addWidget(show_acc)
            layout.addWidget(show_gyr)
            layout.addStretch(1)

            self.__v_box.addLayout(layout)

    def __show_acc(self):
        self.__show_data('ACC_X', 'ACC_Y', 'ACC_Z')

    def __show_gyr(self):
        self.__show_data('GYR_X', 'GYR_Y', 'GYR_Z')

    def __restore_state(self):
        if self.__shared_data.parameter is not None:
            self.__add_selector_acc_gyr()
            self.__show_data('ACC_X', 'ACC_Y', 'ACC_Z')
            print('trigger reimport')
        if self.__shared_data.data_sync is not None:
            text_time = self.__shared_data.data_sync.split(':')
            time = QTime()
            time.setHMS(int(text_time[0]), int(text_time[1]), int(text_time[2]), int(text_time[3]))
            self.__sync_time_edit.setTime(time)