123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QWidget, QAbstractItemView
- from PyQt5.QtGui import QIcon
- from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt
- from view.python_core.get_internal_files import get_internal_icons
- import pandas as pd
- import logging
- class QTableWidgetPandasDF(QTableWidget):
- def __init__(self, parent):
- super().__init__(parent)
- def remove_all_rows(self):
- self.clear()
- self.setRowCount(0)
- def refresh(self, df: pd.DataFrame):
- self.remove_all_rows()
- self.setSortingEnabled(False)
- self.setEditTriggers(QAbstractItemView.NoEditTriggers)
- self.setColumnCount(df.shape[1])
- self.setHorizontalHeaderLabels(df.columns)
- df_no_index = df.reset_index(drop=True)
- for row_ind, row in df_no_index.iterrows():
- table_widget_items = []
- for x in row.values:
- table_widget_item = QTableWidgetItem()
- table_widget_item.setData(Qt.DisplayRole, str(x))
- table_widget_items.append(table_widget_item)
- self._add_row_items(row_index=str(row_ind), items=table_widget_items)
- self.setVerticalHeaderLabels([str(x) for x in df.index.values])
- self.setSortingEnabled(True)
- def get_headers(self):
- return [self.horizontalHeaderItem(col_ind).text() for col_ind in range(self.columnCount())]
- def add_row(self, s: pd.Series):
- cols_input = s.index.values.tolist()
- headers = self.get_headers()
- # if header is empty initialize
- if len(headers) == 0:
- assert self.rowCount() == 0 and self.columnCount() == 0, "Table has entries without headers, cannot " \
- "figure out how to insert entries from series"
- self.setHorizontalHeader(cols_input)
- vals2add = s.values
- else:
- vals2add = {k: v for k, v in enumerate(headers) if v in cols_input}
- cols_missing = set(vals2add.values()) - set(cols_input)
- if len(cols_missing) > 0:
- logging.warning(f"Adding a row: Ignoring the following columns, for which values were not specified: "
- f"{cols_missing}")
- ind_item_mapping = {col_ind: QTableWidgetItem(str(s[col_name]), 0)
- for col_ind, col_name in vals2add.items()}
- self._add_row_items(row_index=s.name, items=ind_item_mapping)
- def _add_row_items(self, row_index: str, items):
- """
- add a row of items
- :param row_index: str, vertical header label for the newly added row
- :param items: list or dict, if dict, keys must be column numbers and values column entries. if list, then
- indices of values will be interpreted as column numbers
- :return:
- """
- assert type(items) in (list, dict)
- if type(items) == list:
- items2use = {k: v for k, v in enumerate(items)}
- else:
- items2use = items
- new_row_ind = self.rowCount()
- self.insertRow(new_row_ind)
- for col_ind, item in items2use.items():
- self.setItem(new_row_ind, col_ind, item)
- self.setVerticalHeaderItem(new_row_ind, QTableWidgetItem(row_index, 0))
- class QTableWidgetPandasDFDeletable(QTableWidgetPandasDF):
- remove_data_signal = pyqtSignal(int, name="delete data")
- def __init__(self, parent):
- super().__init__(parent)
- self.cellClicked.connect(self.send_delete_signal)
- self.horizontalHeader().sectionClicked.connect(self.delete_all)
- def setColumnCount(self, p_int):
- super().setColumnCount(p_int + 1)
- def setItem(self, row_ind: int, col_ind: int, item: QTableWidgetItem):
- super().setItem(row_ind, col_ind + 1, item)
- def setCellWidget(self, row_ind, col_ind, item: QWidget):
- super().setCellWidget(row_ind, col_ind + 1, item)
- def _add_row_items(self, row_index, items):
- super()._add_row_items(row_index, items)
- close_icon = QIcon(get_internal_icons("twotone-delete_forever-24px.svg"))
- super().setItem(self.rowCount() - 1, 0, QTableWidgetItem(close_icon, "", 0))
- def setHorizontalHeaderLabels(self, Iterable, p_str=None):
- super().setHorizontalHeaderLabels([""] + list(Iterable))
- close_icon = QIcon(get_internal_icons("twotone-delete_forever-24px.svg"))
- super().setHorizontalHeaderItem(0, QTableWidgetItem(close_icon, "", 0))
- def get_headers(self):
- to_return = super().get_headers()
- del to_return[0]
- return to_return
- @pyqtSlot(int, int, name="cell clicked")
- def send_delete_signal(self, row_ind, col_ind):
- if col_ind == 0:
- self.removeRow(row_ind)
- self.remove_data_signal.emit(row_ind)
- @pyqtSlot(int, name="header clicked")
- def delete_all(self, col_ind):
- if col_ind == 0:
- row_count = self.rowCount()
- for row_ind in list(range(row_count))[::-1]:
- self.send_delete_signal(row_ind=row_ind, col_ind=0)
|