Source code for polo.widgets.plate_visualizer

import copy
import math

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QFont
from PyQt5.QtGui import *
from polo import IMAGE_CLASSIFICATIONS, make_default_logger
from polo.crystallography.image import Image
from polo.crystallography.run import HWIRun, Run

logger = make_default_logger(__name__)


[docs]class PlateVisualizer(QtWidgets.QGraphicsView): '''The :class:`PlateVisualizer` is a small widget to assist users understand what part of the screening plate they are currently viewing. It renders a grid of rectangles (blocks) that each represent one view (page) in the :class:`PlateInspector` widget. The page that is currently being viewed is highlighted to show the user what part of the plate they are looking at. :param parent: Parent widget, defaults to None :type parent: QWidget, optional ''' plate_view_requested = pyqtSignal(int) default_brush = QBrush(QColor(66, 155, 245)) selected_brush = QBrush(QColor(245, 66, 66)) default_pen = QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine) default_pen.setWidth(2) plate_size = (32, 48) def __init__(self, parent=None): super(PlateVisualizer, self).__init__(parent) self.scene = QtWidgets.QGraphicsScene(self) # self.setInteractive(True) self.setScene(self.scene) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # self.scene.selectionChanged.connect(self._handle_block_selection)
[docs] @staticmethod def block_dims(plate_x, plate_y, grid_x, grid_y): '''Helper method to calculate the size of plate section blocks :param plate_x: Number of wells plate has on its x axis :type plate_x: int :param plate_y: Number of wells plate has on it s y axis :type plate_y: int :param grid_x: Number of wells in the subgrid on its x axis :type grid_x: int :param grid_y: Number of wells in the subgrid on its y axis :type grid_y: int :return: tuple, first item being length of x axis in blocks and second being length of y axis in blocks :rtype: tuple ''' return plate_x / grid_x, plate_y / grid_y
[docs] def _block_size(self, x, y): '''Private method to calculate the size of individual blocks to render in the QGraphicsView. :param x: Length of x-axis in blocks :type x: int :param y: Length of y-axis in blocks :type y: int :return: tuple, length of block x-axis in pixels, length of block y-axis in pixels :rtype: tuple ''' total_width, total_height = ( self.frameGeometry().width(), self.frameGeometry().height() ) return x / total_width, y / total_height
[docs] def _handle_block_selection(self): '''Private helper method to handle when a user selects a block. In theory should open the view that the selected block corresponds to but currently having some issues with this causing segmentation faults so it is disabled for now. ''' if self.scene.selectedItems(): block = self.scene.selectedItems().pop() self._highlight_block(block) self.plate_view_requested.emit(block.data(0))
[docs] def set_selected_block(self, block_id): '''Sets the currently selected block based on its ID. :param block_id: Block ID :type block_id: int ''' for block in self.scene.items(): if block.data(0) == block_id: self._highlight_block(block)
[docs] def _highlight_block(self, block): '''Private method that highlights a block in the QGraphicsScene. :param block: Block to highlight :type block: QGraphicsRectItem ''' for item in self.scene.items(): item.setBrush(self.default_brush) block.setBrush(self.selected_brush)
[docs] def setup_view(self, grid_cords, plate_size=None): '''set up the intail view based on the current plate size (normally 32 * 48 wells for 1536 well plate) and the subgrid size in wells. :param grid_cords: Subgrid size tuple (x, y) in wells :type grid_cords: tuple :param plate_size: Size of entire plate (x, y) in wells, defaults to None. If None used the default 1536 well plate size of 32 * 48. :type plate_size: tuple, optional ''' try: self.scene.clear() g_x, g_y = grid_cords if not plate_size: # assume full size plate p_x, p_y = self.plate_size x, y = (p_x / g_x), (p_y / g_y) # block layout try: x = int(x) y = int(y) except Exception as e: logger.error('Caught {} while calling {}'.format( e, self.setup_view)) return # if cannot be based to int there is a problem w, h = self.frameGeometry().width(), self.frameGeometry().height() w = w / x h = h / y view_id, cur_x, cur_y = 0, 0, 0 for i in range(x): for j in range(y): view_id += 1 rect = self.scene.addRect( cur_x, cur_y, w, h, self.default_pen, self.default_brush) rect.setData(0, view_id) cur_x += w cur_y += h cur_x = 0 self.fitInView(self.scene.itemsBoundingRect()) except Exception as e: logger.error('Caught {} while calling {}'.format( e, self.setup_view)) return
# not worth throwing an error if something goes wrong but a crash # just don't render the visualizer