Source code for pyccapt.calibration.core.gui_ion_select

import sys

import pandas as pd
from PyQt6.QtCore import Qt, QThread
from PyQt6.QtGui import QFont, QGuiApplication
from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget


[docs] class MyWindow(QMainWindow): def __init__(self, data, variables): super().__init__() self.data = data self.variables = variables # Extract the column names and save them in a list self.column_names = data.columns.tolist() self.setWindowTitle("Ions Table") self.setGeometry(100, 100, 800, 400) self.initUI()
[docs] def initUI(self): central_widget = QWidget(self) self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) self.tableWidget = QTableWidget(self) self.tableWidget.setRowCount(len(self.data['ion'])) self.tableWidget.setColumnCount(len(self.data.columns)) # Plus one for the headers # Add the first row for column headers for col, header in enumerate(self.data.columns): header_item = QTableWidgetItem(header) header_font = QFont() header_font.setBold(True) header_item.setFont(header_font) self.tableWidget.setItem(0, col, header_item) for row, (_, row_data) in enumerate(self.data.iterrows()): for col, value in enumerate(row_data): # Use QWebEngineView to render LaTeX formulas if needed if isinstance(value, str) and value.startswith('$') and value.endswith('$'): # Remove dollar signs from the LaTeX formula formula = value[1:-1] # Use QWebEngineView to render the LaTeX formula webview = QWebEngineView(self) webview.setHtml(f'<html><head><script type="text/javascript" async ' 'src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML"></script></head>' f'<body>\\({formula}\\)</body></html>') formula_item = QTableWidgetItem() formula_item.setFlags(formula_item.flags() & ~Qt.ItemFlag.ItemIsEditable) self.tableWidget.setCellWidget(row + 1, col, webview) else: item = QTableWidgetItem(str(value)) self.tableWidget.setItem(row + 1, col, item) layout.addWidget(self.tableWidget) # Set row height for all rows for row in range(self.tableWidget.rowCount()): self.tableWidget.setRowHeight(row, 40) # Set column width for the 'Formula' column (column 0) self.tableWidget.setColumnWidth(0, 200) # self.tableWidget.resizeColumnsToContents() # self.tableWidget.resizeRowsToContents() # Connect the selectionChanged signal to a custom slot self.tableWidget.itemSelectionChanged.connect(self.onSelectionChanged) # Connect column headers to sorting function self.tableWidget.horizontalHeader().sectionClicked.connect(self.sortByColumn)
# Disable selection for column headers # self.tableWidget.horizontalHeader().setSectionsClickable(False)
[docs] def onSelectionChanged(self): # Get the selected row and print its data selected_items = self.tableWidget.selectedItems() header = False # Check if any selected items are in the data region (not in the header row or index column) for item in selected_items: if item.row() == 0: header = True if not header: new_selected_row = selected_items[0].row() selected_row = selected_items[0].row() selected_data = self.data.iloc[selected_row - 1:selected_row] print(selected_data) self.selected_row = new_selected_row # List to match for 'element' and 'complex' target_element_list = selected_data['element'].to_list() target_element_list = [item for sublist in target_element_list for item in sublist] target_complex_list = selected_data['complex'].to_list() target_complex_list = [item for sublist in target_complex_list for item in sublist] # Find rows with matching 'element' and 'complex' lists matching_rows = self.data[ (self.data['element'].apply(lambda x: all(item in x for item in target_element_list))) & (self.data['complex'].apply(lambda x: all(item in x for item in target_complex_list))) ] # Create a new DataFrame with matching rows new_df = pd.DataFrame(matching_rows) # Reset the index of the new DataFrame if needed new_df.reset_index(drop=True, inplace=True) self.variables.ions_list_data = new_df # self.variables.AptHistPlotter.plot_founded_range_loc(new_df) # Disconnect the selectionChanged signal to a custom slot self.tableWidget.itemSelectionChanged.disconnect(self.onSelectionChanged) for col in range(self.tableWidget.columnCount()): item = self.tableWidget.item(self.selected_row, col) if item is not None: item.setSelected(True) # Highlight the item # Connect the selectionChanged signal to a custom slot self.tableWidget.itemSelectionChanged.connect(self.onSelectionChanged)
[docs] def sortByColumn(self, column): # Disable selection for column headers self.tableWidget.horizontalHeader().setSectionsClickable(False) # Disconnect the selectionChanged signal to a custom slot self.tableWidget.itemSelectionChanged.disconnect(self.onSelectionChanged) # Extract data from the table data = [] for row in range(1, self.tableWidget.rowCount()): row_data = [] for col in range(self.tableWidget.columnCount()): item = self.tableWidget.item(row, col) if item is not None: row_data.append(item.text()) else: row_data.append(None) data.append(row_data) # Sort the data by the selected column data.sort(key=lambda row: row[column]) # Update the table with the sorted data for row in range(1, self.tableWidget.rowCount()): for col in range(self.tableWidget.columnCount()): item = self.tableWidget.item(row, col) if item is not None: item.setText(str(data[row - 1][col])) # Enable selection for column headers after sorting self.tableWidget.horizontalHeader().setSectionsClickable(True) # Deselect all rows and columns after sorting self.deselectAllRowsAndColumns() # Connect the selectionChanged signal to a custom slot self.tableWidget.itemSelectionChanged.connect(self.onSelectionChanged)
[docs] def deselectAllRowsAndColumns(self): for row in range(self.tableWidget.rowCount()): for col in range(self.tableWidget.columnCount()): item = self.tableWidget.item(row, col) if item is not None: item.setSelected(False)
if __name__ == '__main__': def open_gui(df, variables): app = 0 # This is the solution to prevent kernel crash of Jupyter lab app = QApplication.instance() if not app: app = QApplication(sys.argv) window = MyWindow(df, variables) window.show() # Ensure that the app is deleted when we close it app.aboutToQuit.connect(app.deleteLater) try: app.exec() except SystemExit: pass