def get_legend_from_graphics_view(legend_widget: pg.GraphicsView): """ Configures and returns a legend widget given a GraphicsView :param legend_widget: instance of GraphicsView object :return: pg.LegendItem """ legend = pg.LegendItem() view_box = pg.ViewBox() legend_widget.setCentralWidget(view_box) legend.setParentItem(view_box) legend.anchor((0, 0), (0, 0)) return legend
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)