def search(self): # first set/change the font of the serach box font = self.dlg.search_lineEdit.font() font.setItalic(False) self.dlg.search_lineEdit.setFont(font) # clear description and quicklook self.dlg.textEdit.clear() # make a new emptey scene to show if not self.dlg.graphicsView is None: scene = QGraphicsScene() pic = QPixmap() scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.show() # function the searches for a string in the datasets name, service type and otganization text = self.dlg.search_lineEdit.text() # convert to lower case and remove greek accents in case of Greek text = text.lower() text = self.removeGreekAccents(text) foundDatasets = [] for dataset in self.datasets: # use lowercase characters and remove greek accents , to make the comparison name = self.removeGreekAccents(dataset.getName(self.language).lower()) source = self.removeGreekAccents(dataset.getSource(self.language).lower()) serviceType = self.removeGreekAccents(dataset.serviceType.lower()) if text in name or text in source or text in serviceType: #QMessageBox.information(None, "DEBUG:", str(type(dataset.getName(self.language)))) foundDatasets.append(dataset) #fill the table with the found datasets self.fill_table(foundDatasets)
def test_editlinksnode(self): from ...registry.tests import small_testing_registry reg = small_testing_registry() file_desc = reg.widget("Orange.OrangeWidgets.Data.OWFile.OWFile") bayes_desc = reg.widget("Orange.OrangeWidgets.Classify.OWNaiveBayes." "OWNaiveBayes") source_node = SchemeNode(file_desc, title="This is File") sink_node = SchemeNode(bayes_desc) scene = QGraphicsScene() view = QGraphicsView(scene) node = EditLinksNode(node=source_node) scene.addItem(node) node = EditLinksNode(direction=Qt.RightToLeft) node.setSchemeNode(sink_node) node.setPos(300, 0) scene.addItem(node) view.show() view.resize(800, 300) self.app.exec_()
class StartSelectView(QGraphicsView): def __init__(self, *args): QGraphicsView.__init__(self, *args) self.move(2, 250) self.btnSize = 28 self.setMaximumHeight(self.btnSize * 2) self.setMaximumWidth(334) self.setMinimumHeight(self.btnSize * 2) self.setMinimumWidth(334) self.adjustSize() self.scene = QGraphicsScene(self) self.setStyleSheet('background-color:transparent; border-width: 0px; border: 0px;') self.psButtons = QPixmap(os.getcwd() + '/../icons/controller-sprite.png') self.select = self.psButtons.copy(696, 120, 45, 30) self.select = self.select.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.selectItem = QGraphicsPixmapItem(self.select) self.selectItem.setOffset(QPointF(0, 0)) self.scene.addItem(self.selectItem) self.start = self.psButtons.copy(754, 120, 45, 30) self.start = self.start.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.startItem = QGraphicsPixmapItem(self.start) self.startItem.setOffset(QPointF(86, 0)) self.scene.addItem(self.startItem) self.setScene(self.scene)
def search(self): # first set/change the font of the serach box font = self.dlg.search_lineEdit.font() font.setItalic(False) self.dlg.search_lineEdit.setFont(font) # clear description and quicklook self.dlg.textEdit.clear() # make a new emptey scene to show if not self.dlg.graphicsView is None: scene = QGraphicsScene() pic = QPixmap() scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.show() # function the searches for a string in the datasets name, service type and otganization text = self.dlg.search_lineEdit.text() # convert to lower case and remove greek accents in case of Greek text = text.lower() text = self.removeGreekAccents(text) foundDatasets = [] for dataset in self.datasets: # use lowercase characters and remove greek accents , to make the comparison name = self.removeGreekAccents(dataset.getName(self.language).lower()) source = self.removeGreekAccents(dataset.getSource(self.language).lower()) serviceType = self.removeGreekAccents(dataset.serviceType.lower()) if text in name or text in source or text in serviceType: #QMessageBox.information(None, "DEBUG:", str(type(dataset.getName(self.language)))) foundDatasets.append(dataset) #fill the table with the found datasets self.fill_table(foundDatasets)
class Ventana(Ui_MainWindow, QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setupUi(self) self.actionOpenImgA.triggered.connect(self.cargarImgA) self.actionOpenImgB.triggered.connect(self.cargarImgB) self.actionOperate.triggered.connect(self.operar) self.escenaA = QGraphicsScene() self.imgA.setScene(self.escenaA) self.escenaB = QGraphicsScene() self.imgB.setScene(self.escenaB) self.escenaC = QGraphicsScene() self.imgC.setScene(self.escenaC) self.operacion.addItem("suma") self.operacion.addItem("multiplicacion") self.operacion.addItem("promedio") def cargarImgA(self): self.imagenA = self.cargarImg(self.escenaA) def cargarImgB(self): self.imagenB = self.cargarImg(self.escenaB) def cargarImg(self, escena): ruta =QFileDialog.getOpenFileName(parent=self, caption="Archivo") imagen = QImage() imagen.load(ruta) pixmap = QPixmap(imagen) escena.addItem(QGraphicsPixmapItem(pixmap)) return imagen def operar(self): ancho = min(self.imagenA.width(), self.imagenB.width()) alto = min(self.imagenA.height(), self.imagenB.height()) oper = getattr(self,str(self.operacion.currentText())) self.imagenC = QImage(ancho, alto, QImage.Format_RGB32 ) for i in range(ancho): for j in range(alto): pix = oper(self.imagenA.pixel(i,j), self.imagenB.pixel(i,j)) self.imagenC.setPixel(i, j, pix) pixmap = QPixmap(self.imagenC) self.escenaC.addItem(QGraphicsPixmapItem(pixmap)) def suma(self, pixA, pixB): return pixA + pixB def multiplicacion(self, pixA, pixB): return pixA * pixB def promedio(self, pixA, pixB): return (pixA + pixB) / 2
def test_editlinksnode(self): from ...registry.tests import small_testing_registry reg = small_testing_registry() file_desc = reg.widget("Orange.widgets.data.owfile.OWFile") bayes_desc = reg.widget("Orange.widgets.classify.ownaivebayes." "OWNaiveBayes") source_node = SchemeNode(file_desc, title="This is File") sink_node = SchemeNode(bayes_desc) scene = QGraphicsScene() view = QGraphicsView(scene) node = EditLinksNode(node=source_node) scene.addItem(node) node = EditLinksNode(direction=Qt.RightToLeft) node.setSchemeNode(sink_node) node.setPos(300, 0) scene.addItem(node) view.show() view.resize(800, 300) self.app.exec_()
class LiteBoxView(QGraphicsView): ALPHA = QColor(0, 0, 0, 192) closed_signal = QtCore.pyqtSignal() def __init__(self, parent=None): super(LiteBoxView, self).__init__(parent) self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint) #self.setAttribute(Qt.WA_DeleteOnClose) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) QtGui.QShortcut( Qt.Key_Escape, self, self.close ) self.desktopshot = None # will propagate to children self.setRenderHint(QPainter.Antialiasing) self.setRenderHint(QPainter.TextAntialiasing) self.scene = QGraphicsScene() self.setScene(self.scene) def close(self): self.closed_signal.emit() super(LiteBoxView, self).close() def drawBackground(self, painter, rect): if self.desktopshot is None: self.desktopshot = get_desktop_pixmap() painter.drawPixmap(self.mapToScene(0, 0), self.desktopshot) painter.setBrush(LiteBoxView.ALPHA) painter.drawRect(rect) def show_fullscreen_svg(self, path): """:param path: path to an svg file""" from PyQt4 import QtSvg item = QtSvg.QGraphicsSvgItem(path) self.show_fullscreen_item(item) def show_fullscreen_pixmap(self, pixmap): """:param pixmap: a QPixmap""" item = QGraphicsPixmapItem(pixmap) self.show_fullscreen_item(item) def show_fullscreen_image(self, image): """:param image: a QImage""" pixmap = QPixmap.fromImage(image) self.show_fullscreen_pixmap( pixmap ) def show_fullscreen_item(self, item): """:param item: a QGraphicsItem to be shown fullscreen""" item.setFlag(QtGui.QGraphicsItem.ItemIsFocusable, True) self.scene.clear() self.scene.addItem(item) CloseMark(parent=item) self.showFullScreen() self.setFocus()
class LiteBoxView(QGraphicsView): ALPHA = QColor(0, 0, 0, 192) closed_signal = QtCore.pyqtSignal() def __init__(self, parent=None): super(LiteBoxView, self).__init__(parent) self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint) #self.setAttribute(Qt.WA_DeleteOnClose) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) QtGui.QShortcut(Qt.Key_Escape, self, self.close) self.desktopshot = None # will propagate to children self.setRenderHint(QPainter.Antialiasing) self.setRenderHint(QPainter.TextAntialiasing) self.scene = QGraphicsScene() self.setScene(self.scene) def close(self): self.closed_signal.emit() super(LiteBoxView, self).close() def drawBackground(self, painter, rect): if self.desktopshot is None: self.desktopshot = get_desktop_pixmap() painter.drawPixmap(self.mapToScene(0, 0), self.desktopshot) painter.setBrush(LiteBoxView.ALPHA) painter.drawRect(rect) def show_fullscreen_svg(self, path): """:param path: path to an svg file""" from PyQt4 import QtSvg item = QtSvg.QGraphicsSvgItem(path) self.show_fullscreen_item(item) def show_fullscreen_pixmap(self, pixmap): """:param pixmap: a QPixmap""" item = QGraphicsPixmapItem(pixmap) self.show_fullscreen_item(item) def show_fullscreen_image(self, image): """:param image: a QImage""" pixmap = QPixmap.fromImage(image) self.show_fullscreen_pixmap(pixmap) def show_fullscreen_item(self, item): """:param item: a QGraphicsItem to be shown fullscreen""" item.setFlag(QtGui.QGraphicsItem.ItemIsFocusable, True) self.scene.clear() self.scene.addItem(item) CloseMark(parent=item) self.showFullScreen() self.setFocus()
class MyWidget(QGraphicsView): def __init__(self): super(MyWidget, self).__init__() self.setFixedSize(300, 300) self.setSceneRect(0, 0, 250, 250) self.scene = QGraphicsScene() self.setScene(self.scene) self.scene.addItem(MyArrow())
def addItem(self, QGraphicsItem): if self.__isNode(QGraphicsItem): QGraphicsItem.setZValue(0.0) QGraphicsItem.onPress.connect(self.__onNodePressed) self.__nodes[QGraphicsItem.Id] = QGraphicsItem QGraphicsScene.addItem(self, QGraphicsItem)
def addItem(self, QGraphicsItem): if self.__isNode(QGraphicsItem): QGraphicsItem.setZValue(1.0) QGraphicsItem.onPress.connect(self.__onNodePressed) self.__nodes[QGraphicsItem.Id] = QGraphicsItem QGraphicsScene.addItem(self, QGraphicsItem)
def test_graphicstextwidget(self): scene = QGraphicsScene() view = QGraphicsView(scene) text = GraphicsTextWidget() text.setHtml("<center><b>a text</b></center><p>paragraph</p>") scene.addItem(text) view.show() view.resize(400, 300) self.app.exec_()
def test_graphicstextwidget(self): scene = QGraphicsScene() view = QGraphicsView(scene) text = GraphicsTextWidget() text.setHtml("<center><b>a text</b></center><p>paragraph</p>") scene.addItem(text) view.show() view.resize(400, 300) self.app.exec_()
class PendulumGraphics(Pendulum): """pendulum which renders itself in a QGraphicsView""" def initGraphics(self, gView): self.gView = gView self.gScene = QGraphicsScene(self.gView) self.gView.setScene(self.gScene) self.gText = QGraphicsTextItem("Pendulum") self.gText.moveBy(0, -120) self.gGrid = Graphics.Items.Grid(size=(-140, -140, 140, 140), xstep=20, ystep=20, toolTip='the main grid') self.gCross = Graphics.Items.CrossX(toolTip='this is the fix point of the pendulum') self.gAxes = Graphics.Items.Axes(toolTip='theese are x,y-axes') self.gPendulum = GPendulum() self.gPendulum.setProperties((self.mass, self.length, self.radius, self.gravity, self.omega, self.friction)) self.gScene.addItem(self.gGrid) self.gScene.addItem(self.gText) self.gScene.addItem(self.gCross) self.gScene.addItem(self.gAxes) self.gScene.addItem(self.gPendulum) self.gView.setSceneRect(QRectF(-140, -140, 280, 280)) self.gPendulum.rotate(self.phi.v) def reset(self): self.gPendulum.rotate(self.initValues['phi']-self.phi.v) Pendulum.reset(self) def update(self, timeStep): Pendulum.update(self, timeStep) self.gPendulum.rotate(self.phiStep)
def axis_view(orientation): ax = pg.AxisItem(orientation=orientation, maxTickLength=7) scene = QGraphicsScene() scene.addItem(ax) view = QGraphicsView( scene, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOff, verticalScrollBarPolicy=Qt.ScrollBarAlwaysOn, alignment=Qt.AlignLeft | Qt.AlignVCenter) view.setFixedHeight(ax.size().height()) ax.line = SliderLine(orientation=Qt.Horizontal, length=ax.size().height()) scene.addItem(ax.line) return view, ax
def axis_view(orientation): ax = pg.AxisItem(orientation=orientation, maxTickLength=7) scene = QGraphicsScene() scene.addItem(ax) view = QGraphicsView( scene, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOff, verticalScrollBarPolicy=Qt.ScrollBarAlwaysOn, alignment=Qt.AlignLeft | Qt.AlignVCenter, ) view.setFixedHeight(ax.size().height()) ax.line = SliderLine(orientation=Qt.Horizontal, length=ax.size().height()) scene.addItem(ax.line) return view, ax
class SingleJoystickView(QGraphicsView): def __init__(self, *args): QGraphicsView.__init__(self, *args) self.outerD = 125 self.innerD = 25 self.innerRange = 50 self.inputRange = 256 self.thresh = 3 self.worker = JoystickThread() self.worker.valueUpdated.connect(self.moveJoystick) self.worker.start() self.move(30, 100) self.setContentsMargins(0, 0, 0, 0) self.setMaximumHeight(140) self.setMaximumWidth(140) self.adjustSize() self.scene = QGraphicsScene(self) self.outerCircle = QGraphicsEllipseItem(0, 0, self.outerD, self.outerD) self.outerCircle.setPen(QPen(QColor(Qt.darkGray), 1, Qt.SolidLine)) self.outerCircle.setBrush(Qt.gray) self.innerCircle = QGraphicsEllipseItem(self.outerD / 2 - self.innerD / 2, self.outerD / 2 - self.innerD / 2, self.innerD, self.innerD) self.innerCircle.setPen(QPen(QColor(Qt.darkGray), 1, Qt.SolidLine)) self.innerCircle.setBrush(Qt.lightGray) self.scene.addItem(self.outerCircle) self.scene.addItem(self.innerCircle) self.setScene(self.scene) self.setStyleSheet('background-color:transparent;color:red') self.currentX = 0 self.currentY = 0 def moveJoystick(self, x, y): x2 = x * self.innerRange / self.inputRange - self.innerRange / 2 y2 = y * self.innerRange / self.inputRange - self.innerRange / 2 if -self.thresh <= x2 <= self.thresh: x2 = 0 if -self.thresh <= y2 <= self.thresh: y2 = 0 self.tl = QTimeLine(10) self.tl.setFrameRange(0, 10) self.a = QGraphicsItemAnimation() self.a.setItem(self.innerCircle) self.a.setTimeLine(self.tl) self.a.setPosAt(0, QPointF(self.currentX, self.currentY)) self.a.setTranslationAt(1, x2, y2) self.currentX = x2 self.currentY = y2 self.tl.start() print 'x:%d y:%d' % (x2, y2)
def dropEvent(self, event): items = self.selectedItems() event.acceptProposedAction() data = event.mimeData().data('application/x-qabstractitemmodeldatalist') text = self.decode_data(data)[0][0].toString() newtable = meta.tables[str(text)] item = Table(newtable, Vector.random()) if items: try: condition = items[0].table.join(newtable) except: condition = None spring = Relation(items[0], item, condition) QGraphicsScene.addItem(self, spring) self.addItem(item)
class FaceButtonsView(QGraphicsView): def __init__(self, *args): QGraphicsView.__init__(self, *args) self.move(170, 90) self.btnSize = 40 self.padding = 5 self.setMaximumHeight(self.btnSize * 4) self.setMaximumWidth(self.btnSize * 4) self.setMinimumHeight(self.btnSize * 4) self.setMinimumWidth(self.btnSize * 4) self.adjustSize() self.setStyleSheet('background-color:transparent; border-width: 0px; border: 0px;') self.scene = QGraphicsScene(self) self.psButtons = QPixmap(os.getcwd() + '/../icons/PS3_Buttons.png') self.triangle = self.psButtons.copy(0, 0, 220, 225) self.triangle = self.triangle.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.square = self.psButtons.copy(220, 0, 220, 225) self.square = self.square.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.circle = self.psButtons.copy(440, 0, 220, 225) self.circle = self.circle.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.cross = self.psButtons.copy(660, 0, 220, 225) self.cross = self.cross.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.triangleItem = QGraphicsPixmapItem(self.triangle) self.triangleItem.setOffset(QPointF(self.btnSize + self.padding, 0)) self.scene.addItem(self.triangleItem) self.squareItem = QGraphicsPixmapItem(self.square) self.squareItem.setOffset(QPointF(0, self.btnSize + self.padding)) self.scene.addItem(self.squareItem) self.circleItem = QGraphicsPixmapItem(self.circle) self.circleItem.setOffset(QPointF(self.btnSize * 2 + self.padding * 2, self.btnSize + self.padding)) self.scene.addItem(self.circleItem) self.crossItem = QGraphicsPixmapItem(self.cross) self.crossItem.setOffset(QPointF(self.btnSize + self.padding, self.btnSize * 2 + self.padding * 2)) self.scene.addItem(self.crossItem) self.effect = QGraphicsDropShadowEffect() self.effect.setOffset(0, 0) self.effect.setBlurRadius(20) self.effect.setColor(Qt.green) self.triangleItem.setGraphicsEffect(self.effect) self.setScene(self.scene) self.tl2 = QTimeLine(10000) self.tl2.setFrameRange(0, 10000) self.t = QGraphicsItemAnimation() self.t.setItem(self.triangleItem) self.t.setTimeLine(self.tl2) self.tl2.connect(self.tl2, SIGNAL('frameChanged(int)'), self.updateEffect) self.effectd = 3 self.tl2.start() def updateEffect(self): if self.effect.blurRadius() > 50: self.effectd = -3 elif self.effect.blurRadius() < 5: self.effectd = 3 self.effect.setBlurRadius(self.effect.blurRadius() + self.effectd)
def main(): app = QApplication(sys.argv) grview = QGraphicsView() scene = QGraphicsScene() scene.setSceneRect(0, 0, 680, 459) scene.addPixmap(QPixmap('01.png')) grview.setScene(scene) item = GraphicsRectItem(0, 0, 300, 150) scene.addItem(item) grview.fitInView(scene.sceneRect(), Qt.KeepAspectRatio) grview.show() sys.exit(app.exec_())
def __init__(self, master, *args): QGraphicsView.__init__(self, *args) self.master = master self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setRenderHints(QPainter.Antialiasing) scene = QGraphicsScene(self) self.pixmapGraphicsItem = QGraphicsPixmapItem(None) scene.addItem(self.pixmapGraphicsItem) self.setScene(scene) self.setMouseTracking(True) self.viewport().setMouseTracking(True) self.setFocusPolicy(Qt.WheelFocus)
def __init__(self, master, *args): QGraphicsView.__init__(self, *args) self.master = master self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setRenderHints(QPainter.Antialiasing) scene = QGraphicsScene(self) self.pixmapGraphicsItem = QGraphicsPixmapItem(None) scene.addItem(self.pixmapGraphicsItem) self.setScene(scene) self.setMouseTracking(True) self.viewport().setMouseTracking(True) self.setFocusPolicy(Qt.WheelFocus)
def close(self): #clear everything self.init_table() # clear description and quicklook self.dlg.textEdit.clear() # clear search box #text = self.dlg.search_lineEdit.setText("") self.init_searchBox() # make a new emptey scene to show if not self.dlg.graphicsView is None: scene = QGraphicsScene() pic = QPixmap() scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.show() """close the dialog""" self.dlg.close()
def __init__(self, app): super(QDialog, self).__init__() #Set up window self.ui = Ui_keySavedDialog() self.ui.setupUi(self) # Set up connections self.ui.okayButton.clicked.connect(self.okayClicked) # Set checkmark image scene = QGraphicsScene() item = QGraphicsPixmapItem(QPixmap("checkmark.png")) scene.addItem(item) self.ui.checkMarkGraphicsView.setScene(scene) self.show()
def close(self): #clear everything self.init_table() # clear description and quicklook self.dlg.textEdit.clear() # clear search box #text = self.dlg.search_lineEdit.setText("") self.init_searchBox() # make a new emptey scene to show if not self.dlg.graphicsView is None: scene = QGraphicsScene() pic = QPixmap() scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.show() """close the dialog""" self.dlg.close()
class DpadView(QGraphicsView): def __init__(self, *args): QGraphicsView.__init__(self, *args) self.move(2, 90) self.btnSize = 75 self.padding = -35 self.setMaximumHeight(self.btnSize * 2 + 20) self.setMaximumWidth(self.btnSize * 2 + 20) self.setMinimumHeight(self.btnSize * 2 + 20) self.setMinimumWidth(self.btnSize * 2 + 20) self.adjustSize() self.setStyleSheet('background-color:transparent; border-width: 0px; border: 0px;') self.scene = QGraphicsScene(self) self.left = QPixmap(os.getcwd() + '/../icons/left.png') self.left = self.left.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.right = QPixmap(os.getcwd() + '/../icons/right.png') self.right = self.right.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.up = QPixmap(os.getcwd() + '/../icons/up.png') self.up = self.up.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.down = QPixmap(os.getcwd() + '/../icons/down.png') self.down = self.down.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.leftItem = QGraphicsPixmapItem(self.left) self.leftItem.setOffset(QPointF(0, self.btnSize + self.padding)) self.scene.addItem(self.leftItem) self.rightItem = QGraphicsPixmapItem(self.right) self.rightItem.setOffset(QPointF(self.btnSize * 2 + self.padding * 2, self.btnSize + self.padding)) self.scene.addItem(self.rightItem) self.upItem = QGraphicsPixmapItem(self.up) self.upItem.setOffset(QPointF(self.btnSize + self.padding, 0)) self.scene.addItem(self.upItem) self.downItem = QGraphicsPixmapItem(self.down) self.downItem.setOffset(QPointF(self.btnSize + self.padding, self.btnSize * 2 + self.padding * 2)) self.scene.addItem(self.downItem) self.effect = QGraphicsDropShadowEffect() self.effect.setOffset(0, 0) self.effect.setBlurRadius(20) self.effect.setColor(Qt.green) self.downItem.setGraphicsEffect(self.effect) self.setScene(self.scene) self.tl2 = QTimeLine(10000) self.tl2.setFrameRange(0, 10000) self.t = QGraphicsItemAnimation() self.t.setItem(self.downItem) self.t.setTimeLine(self.tl2) self.tl2.connect(self.tl2, SIGNAL('frameChanged(int)'), self.updateEffect) self.effectd = 3 self.tl2.start() def updateEffect(self): if self.effect.blurRadius() > 50: self.effectd = -3 elif self.effect.blurRadius() < 5: self.effectd = 3 self.effect.setBlurRadius(self.effect.blurRadius() + self.effectd)
def test(self): raw = numpy.load(os.path.join(volumina._testing.__path__[0], 'lena.npy')).astype( numpy.uint32 ) ars = _ArraySource2d(raw) ims = DummyItemSource(ars) req = ims.request( QRect( 0, 0, 256, 256 ) ) item = req.wait() assert isinstance(item, QGraphicsItem) DEBUG = False if DEBUG: from PyQt4.QtGui import QApplication, QGraphicsView, QGraphicsScene app = QApplication([]) scene = QGraphicsScene() scene.addItem(item) view = QGraphicsView(scene) view.show() view.raise_() app.exec_()
def updateDescAndQL(self): # get the name of the selected dataset dataset_name, dataset_serviceType = self.getSelectedNameAndType() #custom web service object dataset = self.selectdataSets(dataset_name, dataset_serviceType) quicklook = os.path.join(self.quicklooks_dir, dataset.QLname + ".jpg") desc = dataset.getDescription(self.language) name = dataset.getName(self.language) #update decription self.dlg.textEdit.clear() #creation and last update if self.language == "EN": crDate = "Creation date : " + dataset.creationDate update = "Last update : " + dataset.lastUpdate elif self.language == "GR": crDate = unicode( "Ημερομηνια δημιουργιας : " + dataset.creationDate, 'utf-8') update = unicode("Τελευταία ενημέρωση : " + dataset.lastUpdate, 'utf-8') cursor = QTextCursor(self.dlg.textEdit.document()) cursor.insertHtml("<h3> " + name + " <br><br></h3>") cursor.insertHtml("<p> " + desc + " <br><br><br></p>") cursor.insertHtml("<p><i> " + crDate + " <br></i></p>") #cursor.insertHtml("<p><i> "+update+" <br></i></p>") self.dlg.textEdit.setReadOnly(True) #update quicklook #GET DIMENSIONS OF THE IMAGE img = Image.open(quicklook) w, h = img.size scene = QGraphicsScene() pic = QPixmap(quicklook) scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.fitInView(QRectF(0, 0, w, h), Qt.KeepAspectRatio) self.dlg.graphicsView.show()
def test(self): raw = numpy.load( os.path.join(volumina._testing.__path__[0], 'lena.npy')).astype(numpy.uint32) ars = _ArraySource2d(raw) ims = DummyItemSource(ars) req = ims.request(QRect(0, 0, 256, 256)) item = req.wait() assert isinstance(item, QGraphicsItem) DEBUG = False if DEBUG: from PyQt4.QtGui import QApplication, QGraphicsView, QGraphicsScene app = QApplication([]) scene = QGraphicsScene() scene.addItem(item) view = QGraphicsView(scene) view.show() view.raise_() app.exec_()
def render_drop_shadow_frame(pixmap, shadow_rect, shadow_color, offset, radius, rect_fill_color): pixmap.fill(QColor(0, 0, 0, 0)) scene = QGraphicsScene() rect = QGraphicsRectItem(shadow_rect) rect.setBrush(QColor(rect_fill_color)) rect.setPen(QPen(Qt.NoPen)) scene.addItem(rect) effect = QGraphicsDropShadowEffect(color=shadow_color, blurRadius=radius, offset=offset) rect.setGraphicsEffect(effect) scene.setSceneRect(QRectF(QPointF(0, 0), QSizeF(pixmap.size()))) painter = QPainter(pixmap) scene.render(painter) painter.end() scene.clear() scene.deleteLater() return pixmap
def updateDescAndQL(self): # get the name of the selected dataset dataset_name, dataset_serviceType = self.getSelectedNameAndType() #custom web service object dataset = self.selectdataSets(dataset_name,dataset_serviceType) quicklook = os.path.join(self.quicklooks_dir, dataset.QLname+".jpg") desc = dataset.getDescription(self.language) name = dataset.getName(self.language) #update decription self.dlg.textEdit.clear() #creation and last update if self.language =="EN": crDate = "Creation date : "+dataset.creationDate update = "Last update : "+dataset.lastUpdate elif self.language =="GR": crDate = unicode("Ημερομηνια δημιουργιας : "+dataset.creationDate,'utf-8') update = unicode("Τελευταία ενημέρωση : "+dataset.lastUpdate,'utf-8') cursor = QTextCursor(self.dlg.textEdit.document()) cursor.insertHtml("<h3> "+name+" <br><br></h3>") cursor.insertHtml("<p> "+desc+" <br><br><br></p>") cursor.insertHtml("<p><i> "+crDate+" <br></i></p>") #cursor.insertHtml("<p><i> "+update+" <br></i></p>") self.dlg.textEdit.setReadOnly(True) #update quicklook #GET DIMENSIONS OF THE IMAGE img = Image.open(quicklook) w, h = img.size scene = QGraphicsScene() pic = QPixmap(quicklook) scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.fitInView(QRectF(0, 0, w, h), Qt.KeepAspectRatio) self.dlg.graphicsView.show()
def test(self): if not self.winManager: return from PyQt4.QtGui import QGraphicsScene, QGraphicsItem, QGraphicsLineItem from PyQt4.QtCore import QRectF, QLineF w = self.winManager.newWindow() scene = QGraphicsScene(w.graphicsView) scene.addItem(Items.Grid()) scene.addItem(Items.Axes()) line = scene.addLine(QLineF(0, 0, 0, 0)) cross = Items.NodeCross(movable=True) cross.addEdge(line, 1) scene.addItem(cross) help = scene.addText(QCoreApplication.translate('Graphics', 'Press "h" for help!')) help.moveBy(-50, 80) text = Items.NodeText(QCoreApplication.translate('Graphics', 'Drag Me!')) text.setFlag(QGraphicsItem.ItemIsMovable, True) text.setFlag(QGraphicsItem.ItemIsSelectable, True) text.addEdge(line, 2) scene.addItem(text) w.graphicsView.setScene(scene)
def test_editlinksnode(self): reg = small_testing_registry() one_desc = reg.widget("one") negate_desc = reg.widget("negate") source_node = SchemeNode(one_desc, title="This is 1") sink_node = SchemeNode(negate_desc) scene = QGraphicsScene() view = QGraphicsView(scene) node = EditLinksNode(node=source_node) scene.addItem(node) node = EditLinksNode(direction=Qt.RightToLeft) node.setSchemeNode(sink_node) node.setPos(300, 0) scene.addItem(node) view.show() view.resize(800, 300) self.app.exec_()
def __init__(self, parent=None): super(Lectern, self).__init__(parent) self.anchor = None self.initMainMenu() self.initToolbar() splitter = QSplitter() self.tocView = QTreeView() self.tocView.clicked.connect(self.navTo) self.tocModel = TableOfContents() self.tocModel.isEmpty.connect(self.handleTOCLoad) self.tocView.setModel(self.tocModel) self.tocView.expandAll() self.tocView.hide() splitter.addWidget(self.tocView) self.webView = QGraphicsWebView() frame = self.webView.page().mainFrame() scene = QGraphicsScene() scene.addItem(self.webView) self.graphicsView = GraphicsView(scene) self.graphicsView.setFrameShape(QFrame.NoFrame) glWidget = QGLWidget(self) self.graphicsView.setViewport(glWidget) self.webView.loadFinished.connect(self.handleLoad) splitter.addWidget(self.graphicsView) self.setCentralWidget(splitter) self.ebook_info = {} self.setWindowTitle('Lectern') try: self.ebook_info = self.openBook(QApplication.arguments()[1]) except IndexError: pass
def updateLanguage(self): # get the new language language = str(self.dlg.language_comboBox.currentText()) # Change the self.language propertie and change the labe;s if language == "English": self.language = "EN" self.dlg.desc_lbl.setText("Description") self.dlg.preview_lbl.setText("Preview") self.dlg.load_btn.setText("Load") self.dlg.close_btn.setText("Close") self.dlg.search_lbl.setText("Search") self.dlg.info_btn.setText("Info") elif language == "Greek": self.language = "GR" self.dlg.desc_lbl.setText(unicode("Περιγραφή", 'utf-8')) self.dlg.preview_lbl.setText(unicode("Προεπισκόπηση",'utf-8')) self.dlg.load_btn.setText(unicode("Φόρτωση",'utf-8')) self.dlg.close_btn.setText(unicode("Κλείσιμο",'utf-8')) self.dlg.search_lbl.setText(unicode("Αναζήτηση",'utf-8')) self.dlg.info_btn.setText(unicode("Πληροφορίες", 'utf-8')) self.dlg.preview_lbl.setAlignment(Qt.AlignRight) #refill the table self.init_table() # clear description and quicklook self.dlg.textEdit.clear() # clear search box #text = self.dlg.search_lineEdit.setText("") self.init_searchBox() # make a new emptey scene to show if not self.dlg.graphicsView is None: scene = QGraphicsScene() pic = QPixmap() scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.show()
def updateLanguage(self): # get the new language language = str(self.dlg.language_comboBox.currentText()) # Change the self.language propertie and change the labe;s if language == "English": self.language = "EN" self.dlg.desc_lbl.setText("Description") self.dlg.preview_lbl.setText("Preview") self.dlg.load_btn.setText("Load") self.dlg.close_btn.setText("Close") self.dlg.search_lbl.setText("Search") self.dlg.info_btn.setText("Info") elif language == "Greek": self.language = "GR" self.dlg.desc_lbl.setText(unicode("Περιγραφή", 'utf-8')) self.dlg.preview_lbl.setText(unicode("Προεπισκόπηση",'utf-8')) self.dlg.load_btn.setText(unicode("Φόρτωση",'utf-8')) self.dlg.close_btn.setText(unicode("Κλείσιμο",'utf-8')) self.dlg.search_lbl.setText(unicode("Αναζήτηση",'utf-8')) self.dlg.info_btn.setText(unicode("Πληροφορίες", 'utf-8')) self.dlg.preview_lbl.setAlignment(Qt.AlignRight) #refill the table self.init_table() # clear description and quicklook self.dlg.textEdit.clear() # clear search box #text = self.dlg.search_lineEdit.setText("") self.init_searchBox() # make a new emptey scene to show if not self.dlg.graphicsView is None: scene = QGraphicsScene() pic = QPixmap() scene.addItem(QGraphicsPixmapItem(pic)) self.dlg.graphicsView.setScene(scene) self.dlg.graphicsView.show()
class BumpersView(QGraphicsView): def __init__(self, *args): QGraphicsView.__init__(self, *args) self.move(2, 22) self.btnSize = 60 self.setMaximumHeight(60) self.setMaximumWidth(332) self.setMinimumHeight(60) self.setMinimumWidth(332) self.adjustSize() self.scene = QGraphicsScene(self) self.setStyleSheet('background-color:transparent; border-width: 0px; border: 0px;') self.l1 = QPixmap(os.getcwd() + '/../icons/l1.png') self.l1 = self.l1.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.l1Item = QGraphicsPixmapItem(self.l1) self.l1Item.setOffset(QPointF(30, 0)) self.scene.addItem(self.l1Item) self.r1 = QPixmap(os.getcwd() + '/../icons/r1.png') self.r1 = self.l1.scaled(self.btnSize, self.btnSize, Qt.KeepAspectRatio) self.r1Item = QGraphicsPixmapItem(self.r1) self.r1Item.setOffset(QPointF(200, 0)) self.scene.addItem(self.r1Item) self.setScene(self.scene)
def scene(self): scene = QGraphicsScene() scene.addItem(self.background_pixmap_item) scene.addItem(self.head_pixmap_item) return scene
class ClassDiagram(QWidget, itab_item.ITabItem): def __init__(self, actions, parent=None): QWidget.__init__(self, parent) itab_item.ITabItem.__init__(self) self.actions = actions self.graphicView = QGraphicsView(self) self.scene = QGraphicsScene() self.graphicView.setScene(self.scene) self.graphicView.setViewportUpdateMode( QGraphicsView.BoundingRectViewportUpdate) vLayout = QVBoxLayout(self) self.setLayout(vLayout) vLayout.addWidget(self.graphicView) self.scene.setItemIndexMethod(QGraphicsScene.NoIndex) self.scene.setSceneRect(-200, -200, 400, 400) self.graphicView.setMinimumSize(400, 400) actualProject = self.actions.ide.explorer.get_actual_project() arrClasses = self.actions._locator.get_classes_from_project( actualProject) #FIXME:dirty need to fix self.mX = -400 self.mY = -320 self.hightestY = self.mY filesList = [] for elem in arrClasses: #loking for paths filesList.append(elem[2]) for path in set(filesList): self.create_class(path) def create_class(self, path): content = file_manager.read_file_content(path) items = introspection.obtain_symbols(content) mYPadding = 10 mXPadding = 10 for classname, classdetail in list(items["classes"].items()): cl = ClassModel(self.graphicView, self.scene) cl.set_class_name(classname) self.fill_clases(cl, classdetail[1]) self.scene.addItem(cl) cl.setPos(self.mX, self.mY) self.mX += cl._get_width() + mXPadding if self.hightestY < self.mY + cl.get_height(): self.hightestY = self.mY + cl.get_height() if self.mX > 2000: self.mX = -400 self.mY += self.hightestY + mYPadding def fill_clases(self, classComponent, classContent): funct = classContent['functions'] classComponent.set_functions_list(funct) attr = classContent['attributes'] classComponent.set_attributes_list(attr) def scale_view(self, scaleFactor): factor = self.graphicView.transform().scale( scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width() if factor > 0.05 and factor < 15: self.graphicView.scale(scaleFactor, scaleFactor) def keyPressEvent(self, event): taskList = { Qt.Key_Plus: lambda: self.scaleView(1.2), Qt.Key_Minus: lambda: self.scaleView(1 / 1.2) } if (event.key() in taskList): taskList[event.key()]() else: QWidget.keyPressEvent(self, event)
y = mappedParentRect.top( ) + NodeGraphicsItem.LEAFSIZE[1] / 2 elif y > mappedParentRect.bottom( ) - NodeGraphicsItem.LEAFSIZE[1] / 2: y = mappedParentRect.bottom( ) - NodeGraphicsItem.LEAFSIZE[1] / 2 value = QPointF(x, y) elif change == QGraphicsItem.ItemPositionHasChanged: self.model.pos = value if isinstance( value, QPointF) else value.toPointF() return super(NodeGraphicsItem, self).itemChange(change, value) if __name__ == '__main__': from PyQt4.QtGui import QApplication, QGraphicsView, QGraphicsScene from treenode import TreeNode import sys app = QApplication(sys.argv) myview = QGraphicsView() myscene = QGraphicsScene(QRectF(-400, -300, 800, 600)) myview.setScene(myscene) rootnode = TreeNode(0, 'root') parentnode = TreeNode(1, 'grass land', parent=rootnode) leafnode = TreeNode(2, 'grass 1', parent=parentnode) # leafnode2 = TreeNode(3,'earth',parent=parentnode) myscene.addItem(NodeGraphicsItem(parentnode)) myview.show() app.exec_()
class OWSieveDiagram(OWWidget): name = "Sieve Diagram" description = "Visualize the observed and expected frequencies " \ "for a combination of values." icon = "icons/SieveDiagram.svg" priority = 200 inputs = [("Data", Table, "set_data", Default), ("Features", AttributeList, "set_input_features")] outputs = [("Selection", Table)] graph_name = "canvas" want_control_area = False settingsHandler = DomainContextHandler() attrX = ContextSetting("", exclude_metas=False) attrY = ContextSetting("", exclude_metas=False) selection = ContextSetting(set()) def __init__(self): # pylint: disable=missing-docstring super().__init__() self.data = self.discrete_data = None self.attrs = [] self.input_features = None self.areas = [] self.selection = set() self.attr_box = gui.hBox(self.mainArea) model = VariableListModel() model.wrap(self.attrs) combo_args = dict(widget=self.attr_box, master=self, contentsLength=12, callback=self.update_attr, sendSelectedValue=True, valueType=str, model=model) fixed_size = (QSizePolicy.Fixed, QSizePolicy.Fixed) self.attrXCombo = gui.comboBox(value="attrX", **combo_args) gui.widgetLabel(self.attr_box, "\u2715", sizePolicy=fixed_size) self.attrYCombo = gui.comboBox(value="attrY", **combo_args) self.vizrank, self.vizrank_button = SieveRank.add_vizrank( self.attr_box, self, "Score Combinations", self.set_attr) self.vizrank_button.setSizePolicy(*fixed_size) self.canvas = QGraphicsScene() self.canvasView = ViewWithPress(self.canvas, self.mainArea, handler=self.reset_selection) self.mainArea.layout().addWidget(self.canvasView) self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) box = gui.hBox(self.mainArea) box.layout().addWidget(self.graphButton) box.layout().addWidget(self.report_button) def sizeHint(self): return QSize(450, 550) def resizeEvent(self, event): super().resizeEvent(event) self.update_graph() def showEvent(self, event): super().showEvent(event) self.update_graph() def set_data(self, data): """ Discretize continuous attributes, and put all attributes and discrete metas into self.attrs, which is used as a model for combos. Select the first two attributes unless context overrides this. Method `resolve_shown_attributes` is called to use the attributes from the input, if it exists and matches the attributes in the data. Remove selection; again let the context override this. Initialize the vizrank dialog, but don't show it. Args: data (Table): input data """ if isinstance(data, SqlTable) and data.approx_len() > LARGE_TABLE: data = data.sample_time(DEFAULT_SAMPLE_TIME) self.closeContext() self.data = data self.areas = [] self.selection = set() if self.data is None: self.attrs[:] = [] else: if any(attr.is_continuous for attr in data.domain): discretizer = Discretize(method=EqualFreq(n=4), discretize_classes=True, discretize_metas=True) self.discrete_data = discretizer(data) else: self.discrete_data = self.data self.attrs[:] = [ var for var in chain(self.discrete_data.domain, ( var for var in self.data.domain.metas if var.is_discrete)) ] if self.attrs: self.attrX = self.attrs[0].name self.attrY = self.attrs[len(self.attrs) > 1].name else: self.attrX = self.attrY = None self.areas = [] self.selection = set() self.openContext(self.data) self.resolve_shown_attributes() self.update_graph() self.update_selection() self.vizrank.initialize() self.vizrank_button.setEnabled( self.data is not None and len(self.data) > 1 and len(self.data.domain.attributes) > 1) def set_attr(self, attr_x, attr_y): self.attrX, self.attrY = attr_x.name, attr_y.name self.update_attr() def update_attr(self): """Update the graph and selection.""" self.selection = set() self.update_graph() self.update_selection() def set_input_features(self, attr_list): """ Handler for the Features signal. The method stores the attributes and calls `resolve_shown_attributes` Args: attr_list (AttributeList): data from the signal """ self.input_features = attr_list self.resolve_shown_attributes() self.update_selection() def resolve_shown_attributes(self): """ Use the attributes from the input signal if the signal is present and at least two attributes appear in the domain. If there are multiple, use the first two. Combos are disabled if inputs are used. """ self.warning() self.attr_box.setEnabled(True) if not self.input_features: # None or empty return features = [f for f in self.input_features if f in self.attrs] if not features: self.warning( "Features from the input signal are not present in the data") return old_attrs = self.attrX, self.attrY self.attrX, self.attrY = [f.name for f in (features * 2)[:2]] self.attr_box.setEnabled(False) if (self.attrX, self.attrY) != old_attrs: self.selection = set() self.update_graph() def reset_selection(self): self.selection = set() self.update_selection() def select_area(self, area, event): """ Add or remove the clicked area from the selection Args: area (QRect): the area that is clicked event (QEvent): event description """ if event.button() != Qt.LeftButton: return index = self.areas.index(area) if event.modifiers() & Qt.ControlModifier: self.selection ^= {index} else: self.selection = {index} self.update_selection() def update_selection(self): """ Update the graph (pen width) to show the current selection. Filter and output the data. """ if self.areas is None or not self.selection: self.send("Selection", None) return filts = [] for i, area in enumerate(self.areas): if i in self.selection: width = 4 val_x, val_y = area.value_pair filts.append( filter.Values([ filter.FilterDiscrete(self.attrX, [val_x]), filter.FilterDiscrete(self.attrY, [val_y]) ])) else: width = 1 pen = area.pen() pen.setWidth(width) area.setPen(pen) if len(filts) == 1: filts = filts[0] else: filts = filter.Values(filts, conjunction=False) selection = filts(self.discrete_data) if self.discrete_data is not self.data: idset = set(selection.ids) sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset] selection = self.data[sel_idx] self.send("Selection", selection) def update_graph(self): # Function uses weird names like r, g, b, but it does it with utmost # caution, hence # pylint: disable=invalid-name """Update the graph.""" def text(txt, *args, **kwargs): return CanvasText(self.canvas, "", html_text=to_html(txt), *args, **kwargs) def width(txt): return text(txt, 0, 0, show=False).boundingRect().width() def fmt(val): return str(int(val)) if val % 1 == 0 else "{:.2f}".format(val) def show_pearson(rect, pearson, pen_width): """ Color the given rectangle according to its corresponding standardized Pearson residual. Args: rect (QRect): the rectangle being drawn pearson (float): signed standardized pearson residual pen_width (int): pen width (bolder pen is used for selection) """ r = rect.rect() x, y, w, h = r.x(), r.y(), r.width(), r.height() if w == 0 or h == 0: return r = b = 255 if pearson > 0: r = g = max(255 - 20 * pearson, 55) elif pearson < 0: b = g = max(255 + 20 * pearson, 55) else: r = g = b = 224 rect.setBrush(QBrush(QColor(r, g, b))) pen_color = QColor(255 * (r == 255), 255 * (g == 255), 255 * (b == 255)) pen = QPen(pen_color, pen_width) rect.setPen(pen) if pearson > 0: pearson = min(pearson, 10) dist = 20 - 1.6 * pearson else: pearson = max(pearson, -10) dist = 20 - 8 * pearson pen.setWidth(1) def _offseted_line(ax, ay): r = QGraphicsLineItem(x + ax, y + ay, x + (ax or w), y + (ay or h)) self.canvas.addItem(r) r.setPen(pen) ax = dist while ax < w: _offseted_line(ax, 0) ax += dist ay = dist while ay < h: _offseted_line(0, ay) ay += dist def make_tooltip(): """Create the tooltip. The function uses local variables from the enclosing scope.""" # pylint: disable=undefined-loop-variable def _oper(attr_name, txt): if self.data.domain[attr_name] is ddomain[attr_name]: return "=" return " " if txt[0] in "<≥" else " in " return ("<b>{attrX}{xeq}{xval_name}</b>: {obs_x}/{n} ({p_x:.0f} %)" .format(attrX=to_html(attr_x), xeq=_oper(attr_x, xval_name), xval_name=to_html(xval_name), obs_x=fmt(chi.probs_x[x] * n), n=int(n), p_x=100 * chi.probs_x[x]) + "<br/>" + "<b>{attrY}{yeq}{yval_name}</b>: {obs_y}/{n} ({p_y:.0f} %)" .format(attrY=to_html(attr_y), yeq=_oper(attr_y, yval_name), yval_name=to_html(yval_name), obs_y=fmt(chi.probs_y[y] * n), n=int(n), p_y=100 * chi.probs_y[y]) + "<hr/>" + """<b>combination of values: </b><br/> expected {exp} ({p_exp:.0f} %)<br/> observed {obs} ({p_obs:.0f} %)""".format( exp=fmt(chi.expected[y, x]), p_exp=100 * chi.expected[y, x] / n, obs=fmt(chi.observed[y, x]), p_obs=100 * chi.observed[y, x] / n)) for item in self.canvas.items(): self.canvas.removeItem(item) if self.data is None or len(self.data) == 0 or \ self.attrX is None or self.attrY is None: return ddomain = self.discrete_data.domain attr_x, attr_y = self.attrX, self.attrY disc_x, disc_y = ddomain[attr_x], ddomain[attr_y] view = self.canvasView chi = ChiSqStats(self.discrete_data, attr_x, attr_y) n = chi.n max_ylabel_w = max((width(val) for val in disc_y.values), default=0) max_ylabel_w = min(max_ylabel_w, 200) x_off = width(attr_x) + max_ylabel_w y_off = 15 square_size = min(view.width() - x_off - 35, view.height() - y_off - 50) square_size = max(square_size, 10) self.canvasView.setSceneRect(0, 0, view.width(), view.height()) curr_x = x_off max_xlabel_h = 0 self.areas = [] for x, (px, xval_name) in enumerate(zip(chi.probs_x, disc_x.values)): if px == 0: continue width = square_size * px curr_y = y_off for y in range(len(chi.probs_y) - 1, -1, -1): # bottom-up order py = chi.probs_y[y] yval_name = disc_y.values[y] if py == 0: continue height = square_size * py selected = len(self.areas) in self.selection rect = CanvasRectangle(self.canvas, curr_x + 2, curr_y + 2, width - 4, height - 4, z=-10, onclick=self.select_area) rect.value_pair = x, y self.areas.append(rect) show_pearson(rect, chi.residuals[y, x], 3 * selected) rect.setToolTip(make_tooltip()) if x == 0: text(yval_name, x_off, curr_y + height / 2, Qt.AlignRight | Qt.AlignVCenter) curr_y += height xl = text(xval_name, curr_x + width / 2, y_off + square_size, Qt.AlignHCenter | Qt.AlignTop) max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h) curr_x += width bottom = y_off + square_size + max_xlabel_h text(attr_y, 0, y_off + square_size / 2, Qt.AlignLeft | Qt.AlignVCenter, bold=True, vertical=True) text(attr_x, x_off + square_size / 2, bottom, Qt.AlignHCenter | Qt.AlignTop, bold=True) xl = text("χ²={:.2f}, p={:.3f}".format(chi.chisq, chi.p), 0, bottom) # Assume similar height for both lines text("N = " + fmt(chi.n), 0, bottom - xl.boundingRect().height()) def get_widget_name_extension(self): if self.data is not None: return "{} vs {}".format(self.attrX, self.attrY) def send_report(self): self.report_plot()
class Ui_MRMainWindow(Ui_MainWindow): def __init__(self, moviemodel, worker): self._moviemodel = moviemodel self.worker = worker self.job_canceled = False def setupUi(self, MainWindow): super(Ui_MRMainWindow, self).setupUi(MainWindow) self._main_window = MainWindow self.listView.set_model(self._moviemodel) self._graphic_scene = QGraphicsScene() self.movieCoverView.setScene(self._graphic_scene) self.draw_toolbar() QtCore.QObject.connect(self.actionQuit, QtCore.SIGNAL("triggered()"), QtCore.QCoreApplication.instance().quit) QtCore.QObject.connect(self.listView, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.candidates_proposition_menu) QtCore.QObject.connect(self.listView, QtCore.SIGNAL("currentItemChanged(\ QListWidgetItem *,QListWidgetItem *)"), self.load_movie_infos_in_view) QtCore.QObject.connect(self.actionAddFiles, QtCore.SIGNAL("triggered()"), self.add_files) QtCore.QObject.connect(self.actionAddDirectory, QtCore.SIGNAL("triggered()"), self.add_directory) QtCore.QObject.connect(self.actionLaunchRenameAssistant, QtCore.SIGNAL("triggered()"), self.do_compute) QtCore.QObject.connect(self.actionLaunchFromSelection, QtCore.SIGNAL("triggered()"), self.do_compute_from_selection) QtCore.QObject.connect(self.actionSave, QtCore.SIGNAL("triggered()"), self.do_batch_save) QtCore.QObject.connect(self.cancelJobButton, QtCore.SIGNAL("clicked()"), self.canceljob) self.listView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.listView.connect(self.listView, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.onContext) QtCore.QObject.connect(self._main_window, QtCore.SIGNAL("progress(int)"), self.update_progress_bar) QtCore.QObject.connect(self._main_window, QtCore.SIGNAL("statusmessage(QString)"), self.update_status_bar) QtCore.QObject.connect(self.listView, QtCore.SIGNAL("dropped"), self.file_dropped) def draw_toolbar(self): actions = [self.actionAddFiles, self.actionAddDirectory, self.actionLaunchRenameAssistant, self.actionLaunchFromSelection, self.actionSave, self.actionQuit] for action in actions: button = QtGui.QToolButton() button.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) button.addAction(action) button.setDefaultAction(action) self.toolBar.addWidget(button) self.toolBar.show() def file_dropped(self, links): self.build_model_from_files(links) def load_movie_infos_in_view(self, item, previous): if len(self._moviemodel.data()) == 0: print 'modele vide' self.filenamEdit.setText("") self.titleEdit.setText("") self.imdbLinkEdit.setText("") self.descriptionEdit.setText("") self._graphic_scene.clear() return if item == None: return movie = self.listView.item_to_movie[item] self.filenamEdit.setText(movie.get_filename()) self.titleEdit.setText(movie.get_title()) self.imdbLinkEdit.setText(movie.get_imdb_link()) self.descriptionEdit.setText(movie.get_desc()) self._graphic_scene.clear() if movie.get_cover() != "": pixmap = QtGui.QPixmap(movie.get_cover()) pixmap = pixmap.scaled(self.movieCoverView.size()) qitem = QDraggableGraphicsPixmapItem(movie.get_cover(), pixmap) self._graphic_scene.addItem(qitem) def add_files(self): file_extensions = " ".join(map((lambda x: "*." + x), EXTENSIONS)) files = QFileDialog.getOpenFileNames( None, "Select one or more files to open", "/home", "Video Files (" + file_extensions + ")") self.build_model_from_files([unicode(x) for x in files]) def add_directory(self): direct = QFileDialog.getExistingDirectory(None, "Open Directory", "/home", QFileDialog.ShowDirsOnly) self.build_model_from_files([unicode(direct)]) def build_model_from_files(self, files=[]): files = FileTools.recurse_files(files) for movie in xrange(len(files)): m = Movie(files[movie]) self._moviemodel.add_movie(m) def onContext(self, point): if (len(self._moviemodel.data()) == 0) or (self.worker.job != None): return menu = QtGui.QMenu("Context Menu", self._main_window) assist = QtGui.QAction("Rename assistant", None) ignore = QtGui.QAction("Ignore", None) remove = QtGui.QAction("Remove", None) reset = QtGui.QAction("Undo modifications", None) save = QtGui.QAction("Save", None) rmall = QtGui.QAction("Remove all", None) menu.addAction(assist) menu.addAction(reset) menu.addAction(save) #menu.addAction(ignore) menu.addAction(remove) menu.addAction(rmall) res = menu.exec_(self.listView.mapToGlobal(point)) item = self.listView.currentItem() movie = self.listView.item_to_movie[item] if res == save: self._moviemodel.save_movie(movie) if res == remove: self._moviemodel.remove_movie(movie) if res == reset: self._moviemodel.reset_movie_informations(movie) self.load_movie_infos_in_view(item, None) if res == assist: self.worker.do(self.do_compute_sub, movie) if res == ignore: pass if res == rmall: movies = list(self._moviemodel.data()) for movie in movies: self._moviemodel.remove_movie(movie) def candidates_proposition_menu(self, item): movie = self.listView.item_to_movie[item] menu = QtGui.QMenu("Propositions", self._main_window) candidates = self._moviemodel.get_candidates(movie) if(len(candidates) == 0): return tmp = {} if candidates != []: for j in candidates: i = unicode(j) proposition = i[0:min(len(i), 100)] a = QtGui.QAction(proposition, None) tmp[a] = j menu.addAction(a) else: pass res = menu.exec_(QtGui.QCursor.pos()) if res != None: self._moviemodel.affect_candidate(movie, tmp[res]) self.load_movie_infos_in_view(item, None) def do_compute(self): self.worker.do(self.do_compute_sub) def do_compute_from_selection(self): self.worker.do(self.do_compute_sub, selection=True) def update_progress_bar(self, val): self.progressBar.setProperty("value", val) def update_status_bar(self, val): self.statusbar.showMessage(val) def do_compute_sub(self, movie=(), selection=False): self.job_canceled = False self._set_enable_toolbar(False) self._main_window.emit(QtCore.SIGNAL("statusmessage(QString)"), "Querying Google. This may take some time ....") self._main_window.emit(QtCore.SIGNAL("progress(int)"), 0) #allocine_engine = GoogleQuery() allocine_engine = AllocineQuery() google_engine = GoogleQuery() movies = self._moviemodel.data() if movie != (): movies = [movie[0]] if selection: indexes = self.listView.selectedIndexes() if len(indexes) > 0: firstindex = indexes[0] movies = movies[firstindex.row():] for i in xrange(len(movies)): if self.job_canceled: self._main_window.emit(QtCore.SIGNAL("statusmessage(QString)"), "Job cancelled.") break current_movie = movies[i] self._main_window.emit(QtCore.SIGNAL("statusmessage(QString)"), "Processing: %s"%(current_movie.get_title())) query = FileTools.preprocess_query(current_movie.get_title()) propositions = allocine_engine.extract_results(allocine_engine.query(query)) if len(propositions) == 0: propositions = google_engine.extract_results(google_engine.query(query)) def sorter(x,y): if "title" in x.get_imdb_link(): if "title" in y.get_imdb_link(): return 0 return -1 return 1 propositions.sort(sorter) self._moviemodel.set_candidates(current_movie, propositions) if(len(propositions) > 0): self._moviemodel.affect_candidate(current_movie, propositions[0]) self._main_window.emit(QtCore.SIGNAL("progress(int)"), (i + 1) * 100 / len(movies)) time.sleep(SLEEP) self._main_window.emit(QtCore.SIGNAL("progress(int)"), 0) self._main_window.emit(QtCore.SIGNAL("statusmessage(QString)"), "Finished.") self._set_enable_toolbar(True) def do_batch_save(self): self.worker.do(self.do_batch_save_sub) def do_batch_save_sub(self, args, kwargs): data = self._moviemodel.data() for movie in data: if movie.has_changed(): self._moviemodel.save_movie(movie) def canceljob(self): self.job_canceled = True self._main_window.emit(QtCore.SIGNAL("statusmessage(QString)"), "Abording current job. Please wait...") def _set_enable_toolbar(self, enabled): for action in self.toolBar.actions(): action.setEnabled(enabled)
class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.Running = False self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, SCENESIZEX, SCENESIZEY) self.view = QGraphicsView() self.view.setRenderHint(QPainter.Antialiasing) self.view.setScene(self.scene) self.view.setFocusPolicy(Qt.NoFocus) #self.zoomSlider = QSlider(Qt.Horizontal) #self.zoomSlider.setRange(5, 200) #self.zoomSlider.setValue(100) self.pauseButton = QPushButton("Pa&use") self.quitButton = QPushButton("&Quit") layout = QVBoxLayout() layout.addWidget(self.view) #layout.addWidget(self.zoomSlider) layout.addWidget(self.pauseButton) layout.addWidget(self.quitButton) self.setLayout(layout) #self.connect(self.zoomSlider, SIGNAL("valueChanged(int))"), # self.zoom) self.connect(self.pauseButton, SIGNAL("clicked()"), self.pauseOrResume) self.connect(self.quitButton, SIGNAL("clicked()"), self.accept) self.readNodes() self.zoom(1.0) self.populate() #self.startTimer(INTERVAL) self.setWindowTitle("TdPaleo") def pauseOrResume(self): self.Running = not self.Running self.pauseButton.setText("Pa&use" if self.Running else "Res&ume") items = self.scene.items() for item in items: item.setRunning() def zoom(self, value): factor = 1 / 1.5 matrix = self.view.matrix() matrix.reset() matrix.scale(factor, factor) self.view.setMatrix(matrix) def readNodes(self): file = open("tdp_geometry.dat") file.readline() while True: line = file.readline() if not line: break param = line.split(" ") if (line != "\n"): n = node() n.x = float(param[0]) n.y = 956 - float(param[1]) n.angle = float(param[2]) n.d = int(param[3]) n.type = int(param[4]) nodes.append(n) def populate(self): color = QColor(0, 150, 0) head = TdPCavallo(color, nodes[0].angle, QPointF(nodes[0].x, nodes[0].y)) #FIXME AGGIUNGERE POI IL FANTINO AL CAVALLO #segment = Segment(color, offset, head) self.scene.addItem(head) #Running = False def timerEvent(self, event): if not self.Running: return
start = time.time() path_items = generate_path_items_for_labels(pen_table, labels_img, None) print "generate took {}".format(time.time() - start) # 52 ms edges_item = SegmentationEdgesItem(path_items, pen_table) def assign_random_color(id_pair, buttons): print "handling click: {}".format(id_pair) pen = pen_table[id_pair] if pen: pen = QPen(pen) else: pen = QPen() random_color = QColor(*list(np.random.randint(0, 255, (3, )))) pen.setColor(random_color) pen_table[id_pair] = pen edges_item.edgeClicked.connect(assign_random_color) scene = QGraphicsScene() scene.addItem(edges_item) transform = QTransform() transform.scale(5.0, 5.0) view = QGraphicsView(scene) view.setTransform(transform) view.show() view.raise_() app.exec_()
class OWVennDiagram(widget.OWWidget): name = "Venn Diagram" description = "A graphical visualization of an overlap of data instances " \ "from a collection of input data sets." icon = "icons/VennDiagram.svg" inputs = [("Data", Orange.data.Table, "setData", widget.Multiple)] outputs = [("Selected Data", Orange.data.Table)] # Selected disjoint subset indices selection = settings.Setting([]) #: Stored input set hints #: {(index, inputname, attributes): (selectedattrname, itemsettitle)} #: The 'selectedattrname' can be None inputhints = settings.Setting({}) #: Use identifier columns for instance matching useidentifiers = settings.Setting(True) autocommit = settings.Setting(True) want_graph = True def __init__(self): super().__init__() # Diagram update is in progress self._updating = False # Input update is in progress self._inputUpdate = False # All input tables have the same domain. self.samedomain = True # Input datasets in the order they were 'connected'. self.data = OrderedDict() # Extracted input item sets in the order they were 'connected' self.itemsets = OrderedDict() # GUI box = gui.widgetBox(self.controlArea, "Info") self.info = gui.widgetLabel(box, "No data on input\n") self.identifiersBox = gui.radioButtonsInBox( self.controlArea, self, "useidentifiers", [], box="Data Instance Identifiers", callback=self._on_useidentifiersChanged ) self.useequalityButton = gui.appendRadioButton( self.identifiersBox, "Use instance equality" ) rb = gui.appendRadioButton( self.identifiersBox, "Use identifiers" ) self.inputsBox = gui.indentedBox( self.identifiersBox, sep=gui.checkButtonOffsetHint(rb) ) self.inputsBox.setEnabled(bool(self.useidentifiers)) for i in range(5): box = gui.widgetBox(self.inputsBox, "Data set #%i" % (i + 1), addSpace=False) box.setFlat(True) model = itemmodels.VariableListModel(parent=self) cb = QComboBox( minimumContentsLength=12, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon) cb.setModel(model) cb.activated[int].connect(self._on_inputAttrActivated) box.setEnabled(False) # Store the combo in the box for later use. box.combo_box = cb box.layout().addWidget(cb) gui.rubber(self.controlArea) gui.auto_commit(self.controlArea, self, "autocommit", "Commit", "Auto commit") # Main area view self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setRenderHint(QPainter.Antialiasing) self.view.setBackgroundRole(QPalette.Window) self.view.setFrameStyle(QGraphicsView.StyledPanel) self.mainArea.layout().addWidget(self.view) self.vennwidget = VennDiagram() self.vennwidget.resize(400, 400) self.vennwidget.itemTextEdited.connect(self._on_itemTextEdited) self.scene.selectionChanged.connect(self._on_selectionChanged) self.scene.addItem(self.vennwidget) self.resize(self.controlArea.sizeHint().width() + 550, max(self.controlArea.sizeHint().height(), 550)) self._queue = [] self.graphButton.clicked.connect(self.save_graph) @check_sql_input def setData(self, data, key=None): self.error(0) if not self._inputUpdate: # Store hints only on the first setData call. self._storeHints() self._inputUpdate = True if key in self.data: if data is None: # Remove the input self._remove(key) else: # Update existing item self._update(key, data) elif data is not None: # TODO: Allow setting more them 5 inputs and let the user # select the 5 to display. if len(self.data) == 5: self.error(0, "Can only take 5 inputs.") return # Add a new input self._add(key, data) def handleNewSignals(self): self._inputUpdate = False # Check if all inputs are from the same domain. domains = [input.table.domain for input in self.data.values()] samedomain = all(domain_eq(d1, d2) for d1, d2 in pairwise(domains)) self.useequalityButton.setEnabled(samedomain) self.samedomain = samedomain has_identifiers = all(source_attributes(input.table.domain) for input in self.data.values()) if not samedomain and not self.useidentifiers: self.useidentifiers = 1 elif samedomain and not has_identifiers: self.useidentifiers = 0 incremental = all(inc for _, inc in self._queue) if incremental: # Only received updated data on existing link. self._updateItemsets() else: # Links were removed and/or added. self._createItemsets() self._restoreHints() self._updateItemsets() del self._queue[:] self._createDiagram() if self.data: self.info.setText( "{} data sets on input.\n".format(len(self.data))) else: self.info.setText("No data on input\n") self._updateInfo() super().handleNewSignals() def _invalidate(self, keys=None, incremental=True): """ Invalidate input for a list of input keys. """ if keys is None: keys = list(self.data.keys()) self._queue.extend((key, incremental) for key in keys) def itemsetAttr(self, key): index = list(self.data.keys()).index(key) _, combo = self._controlAtIndex(index) model = combo.model() attr_index = combo.currentIndex() if attr_index >= 0: return model[attr_index] else: return None def _controlAtIndex(self, index): group_box = self.inputsBox.layout().itemAt(index).widget() combo = group_box.combo_box return group_box, combo def _setAttributes(self, index, attrs): box, combo = self._controlAtIndex(index) model = combo.model() if attrs is None: model[:] = [] box.setEnabled(False) else: if model[:] != attrs: model[:] = attrs box.setEnabled(True) def _add(self, key, table): name = table.name index = len(self.data) attrs = source_attributes(table.domain) self.data[key] = _InputData(key, name, table) self._setAttributes(index, attrs) self._invalidate([key], incremental=False) item = self.inputsBox.layout().itemAt(index) box = item.widget() box.setTitle("Data set: {}".format(name)) def _remove(self, key): index = list(self.data.keys()).index(key) # Clear possible warnings. self.warning(index) self._setAttributes(index, None) del self.data[key] layout = self.inputsBox.layout() item = layout.takeAt(index) layout.addItem(item) inputs = list(self.data.values()) for i in range(5): box, _ = self._controlAtIndex(i) if i < len(inputs): title = "Data set: {}".format(inputs[i].name) else: title = "Data set #{}".format(i + 1) box.setTitle(title) self._invalidate([key], incremental=False) def _update(self, key, table): name = table.name index = list(self.data.keys()).index(key) attrs = source_attributes(table.domain) self.data[key] = self.data[key]._replace(name=name, table=table) self._setAttributes(index, attrs) self._invalidate([key]) item = self.inputsBox.layout().itemAt(index) box = item.widget() box.setTitle("Data set: {}".format(name)) def _itemsForInput(self, key): useidentifiers = self.useidentifiers or not self.samedomain def items_by_key(key, input): attr = self.itemsetAttr(key) if attr is not None: return [str(inst[attr]) for inst in input.table if not numpy.isnan(inst[attr])] else: return [] def items_by_eq(key, input): return list(map(ComparableInstance, input.table)) input = self.data[key] if useidentifiers: items = items_by_key(key, input) else: items = items_by_eq(key, input) return items def _updateItemsets(self): assert list(self.data.keys()) == list(self.itemsets.keys()) for key, input in list(self.data.items()): items = self._itemsForInput(key) item = self.itemsets[key] item = item._replace(items=items) name = input.name if item.name != name: item = item._replace(name=name, title=name) self.itemsets[key] = item def _createItemsets(self): olditemsets = dict(self.itemsets) self.itemsets.clear() for key, input in self.data.items(): items = self._itemsForInput(key) name = input.name if key in olditemsets and olditemsets[key].name == name: # Reuse the title (which might have been changed by the user) title = olditemsets[key].title else: title = name itemset = _ItemSet(key=key, name=name, title=title, items=items) self.itemsets[key] = itemset def _storeHints(self): if self.data: self.inputhints.clear() for i, (key, input) in enumerate(self.data.items()): attrs = source_attributes(input.table.domain) attrs = tuple(attr.name for attr in attrs) selected = self.itemsetAttr(key) if selected is not None: attr_name = selected.name else: attr_name = None itemset = self.itemsets[key] self.inputhints[(i, input.name, attrs)] = \ (attr_name, itemset.title) def _restoreHints(self): settings = [] for i, (key, input) in enumerate(self.data.items()): attrs = source_attributes(input.table.domain) attrs = tuple(attr.name for attr in attrs) hint = self.inputhints.get((i, input.name, attrs), None) if hint is not None: attr, name = hint attr_ind = attrs.index(attr) if attr is not None else -1 settings.append((attr_ind, name)) else: return # all inputs match the stored hints for i, key in enumerate(self.itemsets): attr, itemtitle = settings[i] self.itemsets[key] = self.itemsets[key]._replace(title=itemtitle) _, cb = self._controlAtIndex(i) cb.setCurrentIndex(attr) def _createDiagram(self): self._updating = True oldselection = list(self.selection) self.vennwidget.clear() n = len(self.itemsets) self.disjoint = disjoint(set(s.items) for s in self.itemsets.values()) vennitems = [] colors = colorpalette.ColorPaletteHSV(n) for i, (key, item) in enumerate(self.itemsets.items()): gr = VennSetItem(text=item.title, count=len(item.items)) color = colors[i] color.setAlpha(100) gr.setBrush(QBrush(color)) gr.setPen(QPen(Qt.NoPen)) vennitems.append(gr) self.vennwidget.setItems(vennitems) for i, area in enumerate(self.vennwidget.vennareas()): area_items = list(map(str, list(self.disjoint[i]))) if i: area.setText("{0}".format(len(area_items))) label = disjoint_set_label(i, n, simplify=False) head = "<h4>|{}| = {}</h4>".format(label, len(area_items)) if len(area_items) > 32: items_str = ", ".join(map(escape, area_items[:32])) hidden = len(area_items) - 32 tooltip = ("{}<span>{}, ...</br>({} items not shown)<span>" .format(head, items_str, hidden)) elif area_items: tooltip = "{}<span>{}</span>".format( head, ", ".join(map(escape, area_items)) ) else: tooltip = head area.setToolTip(tooltip) area.setPen(QPen(QColor(10, 10, 10, 200), 1.5)) area.setFlag(QGraphicsPathItem.ItemIsSelectable, True) area.setSelected(i in oldselection) self._updating = False self._on_selectionChanged() def _updateInfo(self): # Clear all warnings self.warning(list(range(5))) if not len(self.data): self.info.setText("No data on input\n") else: self.info.setText( "{0} data sets on input\n".format(len(self.data))) if self.useidentifiers: for i, key in enumerate(self.data): if not source_attributes(self.data[key].table.domain): self.warning(i, "Data set #{} has no suitable identifiers." .format(i + 1)) def _on_selectionChanged(self): if self._updating: return areas = self.vennwidget.vennareas() indices = [i for i, area in enumerate(areas) if area.isSelected()] self.selection = indices self.invalidateOutput() def _on_useidentifiersChanged(self): self.inputsBox.setEnabled(self.useidentifiers == 1) # Invalidate all itemsets self._invalidate() self._updateItemsets() self._createDiagram() self._updateInfo() def _on_inputAttrActivated(self, attr_index): combo = self.sender() # Find the input index to which the combo box belongs # (they are reordered when removing inputs). index = None inputs = list(self.data.items()) for i in range(len(inputs)): _, c = self._controlAtIndex(i) if c is combo: index = i break assert (index is not None) key, _ = inputs[index] self._invalidate([key]) self._updateItemsets() self._createDiagram() def _on_itemTextEdited(self, index, text): text = str(text) key = list(self.itemsets.keys())[index] self.itemsets[key] = self.itemsets[key]._replace(title=text) def invalidateOutput(self): self.commit() def commit(self): selected_subsets = [] selected_items = reduce( set.union, [self.disjoint[index] for index in self.selection], set() ) def match(val): if numpy.isnan(val): return False else: return str(val) in selected_items source_var = Orange.data.StringVariable("source") item_id_var = Orange.data.StringVariable("item_id") names = [itemset.title.strip() for itemset in self.itemsets.values()] names = uniquify(names) for i, (key, input) in enumerate(self.data.items()): if self.useidentifiers: attr = self.itemsetAttr(key) if attr is not None: mask = list(map(match, (inst[attr] for inst in input.table))) else: mask = [False] * len(input.table) def instance_key(inst): return str(inst[attr]) else: mask = [ComparableInstance(inst) in selected_items for inst in input.table] _map = {item: str(i) for i, item in enumerate(selected_items)} def instance_key(inst): return _map[ComparableInstance(inst)] mask = numpy.array(mask, dtype=bool) subset = Orange.data.Table(input.table.domain, input.table[mask]) subset.ids = input.table.ids[mask] if len(subset) == 0: continue # add columns with source table id and set id id_column = numpy.array([[instance_key(inst)] for inst in subset], dtype=object) source_names = numpy.array([[names[i]]] * len(subset), dtype=object) subset = append_column(subset, "M", source_var, source_names) subset = append_column(subset, "M", item_id_var, id_column) selected_subsets.append(subset) if selected_subsets: data = table_concat(selected_subsets) # Get all variables which are not constant between the same # item set varying = varying_between(data, [item_id_var]) if source_var in varying: varying.remove(source_var) data = reshape_wide(data, varying, [item_id_var], [source_var]) # remove the temporary item set id column data = drop_columns(data, [item_id_var]) else: data = None self.send("Selected Data", data) def getSettings(self, *args, **kwargs): self._storeHints() return super().getSettings(self, *args, **kwargs) def save_graph(self): from Orange.widgets.data.owsave import OWSave save_img = OWSave(data=self.scene, file_formats=FileFormat.img_writers) save_img.exec_()
class DualImageView(QGraphicsView): VERTICAL = 0 HORIZONTAL = 1 IMAGE_A = 0 IMAGE_B = 1 # no argument signal images_changed = pyqtSignal() annotations_changed = pyqtSignal() annotation_selected = pyqtSignal(int) no_selection = pyqtSignal() # click/point signals image_a_click = pyqtSignal(int,int) image_b_click = pyqtSignal(int,int) # keyboard key_event = pyqtSignal(int) def __init__(self, main_win): super(QGraphicsView,self).__init__(main_win) self.parent_ = main_win self.main_win_ = main_win self.setInteractive(True) self.setStyleSheet("QGraphicsView { border: none; }") self.scene_ = QGraphicsScene(0,0,0,0,self.parent_) self.image_item_ = self.scene_.addPixmap(QPixmap()) self.image_item_.setPos(0,0) #self.ann_group_ = QGraphicsItemGroup() #self.ann_group_.setPos(0,0) #self.scene_.addItem(self.ann_group_) self.setScene(self.scene_) self.scene_.selectionChanged.connect(self.on_selection_changed) # TODO: handle orientation self.orientation_ = DualImageView.VERTICAL self.images_ = [None, None] self.composite_ = None self.annotations_ = [] self.dim_ = 0 self.offset_ = np.array([0,0]) self.cancel_click_ = False self.images_changed.connect(self.on_images_changed) self.annotations_changed.connect(self.on_annotations_changed) def on_selection_changed(self): log.debug("on_selection_changed") selected = self.scene_.selectedItems() if len(selected) > 0: self.cancel_click_ = True selected = self.scene_.selectedItems()[0] idx = -1 for a in self.annotations_: idx += 1 if a.item == selected: log.debug(" emitting selection {0}".format(idx)) self.annotation_selected.emit(idx) else: self.no_selection.emit() @property def image_b_offset(self): return np.array([0,self.dim_],dtype=np.int32) def point_in_image(self, p): if p[1] < self.dim_: return 0 else: return 1 def point_to_image(self, which, p): if which == DualImageView.IMAGE_B: return p - self.image_b_offset return p def image_to_view(self, which, p): if which == DualImageView.IMAGE_B: return p + self.image_b_offset return p def on_images_changed(self): imga = self.images_[0] imgb = self.images_[1] width = max(imga.shape[1],imgb.shape[1]) heighta = imga.shape[0] heightb = imgb.shape[0] height = heighta + heightb self.dim_ = heighta self.offset_ = np.array([0,heighta]) # this assumes rgb images :-( comp = np.empty((height,width,imga.shape[2]),dtype=imga.dtype) comp[0:heighta,:imga.shape[1],:] = imga comp[heighta:(heighta+heightb),:imgb.shape[1],:] = imgb self.composite_ = comp qimg = qn.array2qimage(self.composite_) pix = QPixmap.fromImage(qimg) self.image_item_.setPixmap(pix) self.scene_.setSceneRect(0,0, width, height) self.repaint() def on_annotations_changed(self): #log.debug("on_annotations_changed") # self.scene_.removeItem(self.ann_group_) # self.ann_group_ = QGraphicsItemGroup() # self.ann_group_.setHandlesChildEvents(False) # self.ann_group_.setPos(0,0) # for a in self.annotations_: # log.debug(" adding item") # self.ann_group_.addToGroup(a.get_item()) # self.scene_.addItem(self.ann_group_) self.repaint() def transform_raw_pt(self, ev): pt = self.mapToScene(ev.x(), ev.y()) return np.array([int(pt.x()), int(pt.y())], dtype=np.int32) def clear(self): self.images_ = [None,None] self.composite_ = None self.annotations_ = None self.images_changed.emit() self.annotations_changed.emit() def set_images(self, img_pair): self.images_ = img_pair self.images_changed.emit() # @property # def annotations(self): # return self.annotations_ # @annotations.setter # def annotations(self, anns): # self.annotations_ = anns # self.annotations_changed.emit() # def set_annotations(self, anns): # self.annotations_ = anns # self.annotations_changed.emit() def paintEvent(self, ev): painter = QPainter(self.viewport()) painter.fillRect(0,0,self.viewport().width(),self.viewport().height(), QColor(0,0,0)) painter.end() QGraphicsView.paintEvent(self, ev) def annotation(self, idx): return self.annotations_[idx] def clear_annotations(self): for a in self.annotations_: self.scene_.removeItem(a.item) self.annotations_ = [] self.annotations_changed.emit() def add_annotation(self, ann): ann.changed.connect(self.on_annotations_changed) self.annotations_.append(ann) self.scene_.addItem(ann.item) self.annotations_changed.emit() return len(self.annotations_) - 1 def remove_last_annotation(self): self.scene_.removeItem(self.annotations_[-1].item) del self.annotations_[-1] self.annotations_changed.emit() def remove_annotation(self, idx): self.scene_.removeItem(self.annotations_[idx].item) del self.annotations_[idx] self.annotations_changed.emit() def mousePressEvent(self, ev): super(DualImageView,self).mousePressEvent(ev) if self.cancel_click_: return log.debug("mouse pressed: " + str(ev)) self.img_local_pt = self.transform_raw_pt(ev) def mouseReleaseEvent(self, ev): super(DualImageView,self).mouseReleaseEvent(ev) if self.cancel_click_: self.cancel_click_ = False return log.debug("mouse released: " + str(ev)) rel_pt = self.transform_raw_pt(ev) delta = rel_pt - self.img_local_pt if abs(delta[0]) < 3 and abs(delta[1] < 3): # it was a successful click self.mouseClicked(self.img_local_pt) else: # recognize this as a rectangle drag self.mouseDragged(self.img_local_pt, delta) def mouseDragged(self, pt, delta): log.debug("mouse dragged: {0}, {1}".format(pt,delta)) def mouseClicked(self, pt): log.debug("mouse clicked: {0}".format(pt)) if pt[1] < self.dim_: self.image_a_click.emit(pt[0],pt[1]) else: self.image_b_click.emit(pt[0],pt[1] - self.dim_) # handle the keyboard events here! def keyPressEvent(self, ev): pass def keyReleaseEvent(self, ev): k = ev.key() self.key_event.emit(k)
class OWHierarchicalClustering(widget.OWWidget): name = "Hierarchical Clustering" description = ("Hierarchical clustering based on distance matrix, and " "a dendrogram viewer.") icon = "icons/HierarchicalClustering.svg" priority = 2100 inputs = [("Distances", Orange.misc.DistMatrix, "set_distances")] outputs = [("Selected Data", Orange.data.Table), ("Other Data", Orange.data.Table)] #: Selected linkage linkage = settings.Setting(1) #: Index of the selected annotation item (variable, ...) annotation_idx = settings.Setting(0) #: Selected tree pruning (none/max depth) pruning = settings.Setting(0) #: Maximum depth when max depth pruning is selected max_depth = settings.Setting(10) #: Selected cluster selection method (none, cut distance, top n) selection_method = settings.Setting(0) #: Cut height ratio wrt root height cut_ratio = settings.Setting(75.0) #: Number of top clusters to select top_n = settings.Setting(3) append_clusters = settings.Setting(True) cluster_role = settings.Setting(2) cluster_name = settings.Setting("Cluster") autocommit = settings.Setting(False) #: Cluster variable domain role AttributeRole, ClassRole, MetaRole = 0, 1, 2 def __init__(self, parent=None): super().__init__(parent) self.matrix = None self.items = None self.linkmatrix = None self.root = None self._displayed_root = None self.cutoff_height = 0.0 self._invalidated = False gui.comboBox(gui.widgetBox(self.controlArea, "Linkage"), self, "linkage", items=LINKAGE, callback=self._invalidate_clustering) box = gui.widgetBox(self.controlArea, "Annotation") self.label_cb = gui.comboBox(box, self, "annotation_idx", callback=self._update_labels) self.label_cb.setModel(itemmodels.VariableListModel()) self.label_cb.model()[:] = ["None", "Enumeration"] box = gui.radioButtons(self.controlArea, self, "pruning", box="Pruning", callback=self._invalidate_pruning) grid = QGridLayout() box.layout().addLayout(grid) grid.addWidget(gui.appendRadioButton(box, "None", addToLayout=False), 0, 0) self.max_depth_spin = gui.spin(box, self, "max_depth", minv=1, maxv=100, callback=self._invalidate_pruning, keyboardTracking=False) grid.addWidget( gui.appendRadioButton(box, "Max depth", addToLayout=False), 1, 0) grid.addWidget(self.max_depth_spin, 1, 1) box = gui.radioButtons(self.controlArea, self, "selection_method", box="Selection", callback=self._selection_method_changed) grid = QGridLayout() box.layout().addLayout(grid) grid.addWidget(gui.appendRadioButton(box, "Manual", addToLayout=False), 0, 0) grid.addWidget( gui.appendRadioButton(box, "Height ratio", addToLayout=False), 1, 0) self.cut_ratio_spin = gui.spin(box, self, "cut_ratio", 0, 100, step=1e-1, spinType=float, callback=self._selection_method_changed) self.cut_ratio_spin.setSuffix("%") grid.addWidget(self.cut_ratio_spin, 1, 1) grid.addWidget(gui.appendRadioButton(box, "Top N", addToLayout=False), 2, 0) self.top_n_spin = gui.spin(box, self, "top_n", 1, 20, callback=self._selection_method_changed) grid.addWidget(self.top_n_spin, 2, 1) box.layout().addLayout(grid) self.controlArea.layout().addStretch() box = gui.widgetBox(self.controlArea, "Output") gui.checkBox(box, self, "append_clusters", "Append cluster IDs", callback=self._invalidate_output) ibox = gui.indentedBox(box) name_edit = gui.lineEdit(ibox, self, "cluster_name") name_edit.editingFinished.connect(self._invalidate_output) cb = gui.comboBox( ibox, self, "cluster_role", callback=self._invalidate_output, items=["Attribute", "Class variable", "Meta variable"]) form = QFormLayout(fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow, labelAlignment=Qt.AlignLeft, spacing=8) form.addRow("Name", name_edit) form.addRow("Place", cb) ibox.layout().addSpacing(5) ibox.layout().addLayout(form) ibox.layout().addSpacing(5) cb = gui.checkBox(box, self, "autocommit", "Commit automatically") b = gui.button(box, self, "Commit", callback=self.commit, default=True) gui.setStopper(self, b, cb, "_invalidated", callback=self.commit) self.scene = QGraphicsScene() self.view = QGraphicsView( self.scene, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOff, verticalScrollBarPolicy=Qt.ScrollBarAlwaysOn, alignment=Qt.AlignLeft | Qt.AlignVCenter) def axis_view(orientation): ax = pg.AxisItem(orientation=orientation, maxTickLength=7) scene = QGraphicsScene() scene.addItem(ax) view = QGraphicsView( scene, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOff, verticalScrollBarPolicy=Qt.ScrollBarAlwaysOn, alignment=Qt.AlignLeft | Qt.AlignVCenter) view.setFixedHeight(ax.size().height()) ax.line = SliderLine(orientation=Qt.Horizontal, length=ax.size().height()) scene.addItem(ax.line) return view, ax self.top_axis_view, self.top_axis = axis_view("top") self.mainArea.layout().setSpacing(1) self.mainArea.layout().addWidget(self.top_axis_view) self.mainArea.layout().addWidget(self.view) self.bottom_axis_view, self.bottom_axis = axis_view("bottom") self.mainArea.layout().addWidget(self.bottom_axis_view) self._main_graphics = QGraphicsWidget() self._main_layout = QGraphicsLinearLayout(Qt.Horizontal) self._main_layout.setSpacing(1) self._main_graphics.setLayout(self._main_layout) self.scene.addItem(self._main_graphics) self.dendrogram = DendrogramWidget() self.dendrogram.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.dendrogram.selectionChanged.connect(self._invalidate_output) self.dendrogram.selectionEdited.connect(self._selection_edited) fm = self.fontMetrics() self.dendrogram.setContentsMargins(5, fm.lineSpacing() / 2, 5, fm.lineSpacing() / 2) self.labels = GraphicsSimpleTextList() self.labels.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.labels.setAlignment(Qt.AlignLeft) self.labels.setMaximumWidth(200) self.labels.layout().setSpacing(0) self._main_layout.addItem(self.dendrogram) self._main_layout.addItem(self.labels) self._main_layout.setAlignment(self.dendrogram, Qt.AlignLeft | Qt.AlignVCenter) self._main_layout.setAlignment(self.labels, Qt.AlignLeft | Qt.AlignVCenter) self.view.viewport().installEventFilter(self) self.top_axis_view.viewport().installEventFilter(self) self.bottom_axis_view.viewport().installEventFilter(self) self._main_graphics.installEventFilter(self) self.cut_line = SliderLine(self.dendrogram, orientation=Qt.Horizontal) self.cut_line.valueChanged.connect(self._dendrogram_slider_changed) self.cut_line.hide() self.bottom_axis.line.valueChanged.connect(self._axis_slider_changed) self.top_axis.line.valueChanged.connect(self._axis_slider_changed) self.dendrogram.geometryChanged.connect(self._dendrogram_geom_changed) self._set_cut_line_visible(self.selection_method == 1) def set_distances(self, matrix): self.matrix = matrix self._invalidate_clustering() self._set_items(matrix.row_items if matrix is not None else None) def _set_items(self, items): self.items = items if items is None: self.label_cb.model()[:] = ["None", "Enumeration"] elif isinstance(items, Orange.data.Table): vars = list(items.domain) self.label_cb.model()[:] = ["None", "Enumeration"] + vars elif isinstance(items, list) and \ all(isinstance(var, Orange.data.Variable) for var in items): self.label_cb.model()[:] = ["None", "Enumeration", "Name"] else: self.label_cb.model()[:] = ["None", "Enumeration"] self.annotation_idx = min(self.annotation_idx, len(self.label_cb.model()) - 1) def handleNewSignals(self): self._update_labels() def _clear_plot(self): self.labels.set_labels([]) self.dendrogram.set_root(None) def _set_displayed_root(self, root): self._clear_plot() self._displayed_root = root self.dendrogram.set_root(root) self._update_labels() self._main_graphics.resize( self._main_graphics.size().width(), self._main_graphics.sizeHint(Qt.PreferredSize).height()) self._main_graphics.layout().activate() def _update(self): self._clear_plot() distances = self.matrix if distances is not None: # Convert to flat upper triangular distances i, j = numpy.triu_indices(distances.X.shape[0], k=1) distances = distances.X[i, j] method = LINKAGE[self.linkage].lower() Z = scipy.cluster.hierarchy.linkage(distances, method=method) tree = tree_from_linkage(Z) self.linkmatrix = Z self.root = tree self.top_axis.setRange(tree.value.height, 0.0) self.bottom_axis.setRange(tree.value.height, 0.0) if self.pruning: self._set_displayed_root(prune(tree, level=self.max_depth)) else: self._set_displayed_root(tree) else: self.linkmatrix = None self.root = None self._set_displayed_root(None) self._apply_selection() def _update_labels(self): labels = [] if self.root and self._displayed_root: indices = [leaf.value.index for leaf in leaves(self.root)] if self.annotation_idx == 0: labels = [] elif self.annotation_idx == 1: labels = [str(i) for i in indices] elif isinstance(self.items, Orange.data.Table): var = self.label_cb.model()[self.annotation_idx] col = self.items[:, var] labels = [var.repr_val(next(iter(row))) for row in col] labels = [labels[idx] for idx in indices] else: labels = [] if labels and self._displayed_root is not self.root: joined = leaves(self._displayed_root) labels = [ ", ".join(labels[leaf.value.first:leaf.value.last]) for leaf in joined ] self.labels.set_labels(labels) self.labels.setMinimumWidth(1 if labels else -1) def _invalidate_clustering(self): self._update() self._update_labels() def _invalidate_output(self): self._invalidated = True if self.autocommit: self.commit() def _invalidate_pruning(self): if self.root: selection = self.dendrogram.selected_nodes() ranges = [node.value.range for node in selection] if self.pruning: self._set_displayed_root(prune(self.root, level=self.max_depth)) else: self._set_displayed_root(self.root) selected = [ node for node in preorder(self._displayed_root) if node.value.range in ranges ] self.dendrogram.set_selected_clusters(selected) self._apply_selection() def commit(self): self._invalidated = False items = getattr(self.matrix, "items", self.items) if not items: # nothing to commit return selection = self.dendrogram.selected_nodes() selection = sorted(selection, key=lambda c: c.value.first) indices = [leaf.value.index for leaf in leaves(self.root)] maps = [ indices[node.value.first:node.value.last] for node in selection ] selected_indices = list(chain(*maps)) unselected_indices = sorted( set(range(self.root.value.last)) - set(selected_indices)) selected = [items[k] for k in selected_indices] unselected = [items[k] for k in unselected_indices] if not selected: self.send("Selected Data", None) self.send("Other Data", None) return selected_data = unselected_data = None if isinstance(items, Orange.data.Table): c = numpy.zeros(len(items)) for i, indices in enumerate(maps): c[indices] = i c[unselected_indices] = len(maps) mask = c != len(maps) if self.append_clusters: clust_var = Orange.data.DiscreteVariable( str(self.cluster_name), values=[ "Cluster {}".format(i + 1) for i in range(len(maps)) ] + ["Other"]) data, domain = items, items.domain attrs = domain.attributes class_ = domain.class_vars metas = domain.metas X, Y, M = data.X, data.Y, data.metas if self.cluster_role == self.AttributeRole: attrs = attrs + (clust_var, ) X = numpy.c_[X, c] elif self.cluster_role == self.ClassRole: class_ = class_ + (clust_var, ) Y = numpy.c_[Y, c] elif self.cluster_role == self.MetaRole: metas = metas + (clust_var, ) M = numpy.c_[M, c] domain = Orange.data.Domain(attrs, class_, metas) data = Orange.data.Table(domain, X, Y, M) else: data = items if selected: selected_data = data[mask] if unselected: unselected_data = data[~mask] self.send("Selected Data", selected_data) self.send("Other Data", unselected_data) def sizeHint(self): return QSize(800, 500) def eventFilter(self, obj, event): if obj is self.view.viewport() and event.type() == QEvent.Resize: width = self.view.viewport().width() - 2 self._main_graphics.setMaximumWidth(width) self._main_graphics.setMinimumWidth(width) self._main_graphics.layout().activate() elif event.type() == QEvent.MouseButtonPress and \ (obj is self.top_axis_view.viewport() or obj is self.bottom_axis_view.viewport()): self.selection_method = 1 # Map click point to cut line local coordinates pos = self.top_axis_view.mapToScene(event.pos()) cut = self.top_axis.line.mapFromScene(pos) self.top_axis.line.setValue(cut.x()) # update the line visibility, output, ... self._selection_method_changed() return super().eventFilter(obj, event) def _dendrogram_geom_changed(self): pos = self.dendrogram.pos_at_height(self.cutoff_height) geom = self.dendrogram.geometry() crect = self.dendrogram.contentsRect() self._set_slider_value(pos.x(), geom.width()) self.cut_line.setLength(geom.height()) self.top_axis.resize(crect.width(), self.top_axis.height()) self.top_axis.setPos(geom.left() + crect.left(), 0) self.top_axis.line.setPos(self.cut_line.scenePos().x(), 0) self.bottom_axis.resize(crect.width(), self.bottom_axis.height()) self.bottom_axis.setPos(geom.left() + crect.left(), 0) self.bottom_axis.line.setPos(self.cut_line.scenePos().x(), 0) geom = self._main_graphics.geometry() assert geom.topLeft() == QPointF(0, 0) self.scene.setSceneRect(geom) geom.setHeight(self.top_axis.size().height()) self.top_axis.scene().setSceneRect(geom) self.bottom_axis.scene().setSceneRect(geom) def _axis_slider_changed(self, value): self.cut_line.setValue(value) def _dendrogram_slider_changed(self, value): p = QPointF(value, 0) cl_height = self.dendrogram.height_at(p) self.set_cutoff_height(cl_height) # Sync the cut positions between the dendrogram and the axis. self._set_slider_value(value, self.dendrogram.size().width()) def _set_slider_value(self, value, span): with blocked(self.cut_line): self.cut_line.setValue(value) self.cut_line.setRange(0, span) with blocked(self.top_axis.line): self.top_axis.line.setValue(value) self.top_axis.line.setRange(0, span) with blocked(self.bottom_axis.line): self.bottom_axis.line.setValue(value) self.bottom_axis.line.setRange(0, span) def set_cutoff_height(self, height): self.cutoff_height = height if self.root: self.cut_ratio = 100 * height / self.root.value.height self.select_max_height(height) def _set_cut_line_visible(self, visible): self.cut_line.setVisible(visible) self.top_axis.line.setVisible(visible) self.bottom_axis.line.setVisible(visible) def select_top_n(self, n): root = self._displayed_root if root: clusters = top_clusters(root, n) self.dendrogram.set_selected_clusters(clusters) def select_max_height(self, height): root = self._displayed_root if root: clusters = clusters_at_height(root, height) self.dendrogram.set_selected_clusters(clusters) def _selection_method_changed(self): self._set_cut_line_visible(self.selection_method == 1) if self.root: self._apply_selection() def _apply_selection(self): if not self.root: return if self.selection_method == 0: pass elif self.selection_method == 1: height = self.cut_ratio * self.root.value.height / 100 self.set_cutoff_height(height) pos = self.dendrogram.pos_at_height(height) self._set_slider_value(pos.x(), self.dendrogram.size().width()) elif self.selection_method == 2: self.select_top_n(self.top_n) def _selection_edited(self): # Selection was edited by clicking on a cluster in the # dendrogram view. self.selection_method = 0 self._selection_method_changed()
self._resizeState = True self._location = self.pos() event.accept() def mouseReleaseEvent(self, event): self._resizeState = False event.accept() def mouseMoveEvent(self, event): if self._resizeState: change = event.pos() - event.lastPos() if self._parent.resizeRect(self._position, self._location + change): self._location += change self.prepareGeometryChange() self.setPos(self._location) event.accept() if __name__ == '__main__': from PyQt4.QtGui import QApplication, QGraphicsView, QGraphicsScene import sys app = QApplication(sys.argv) myview = QGraphicsView() myscene = QGraphicsScene(QRectF(-400, -300, 800, 600)) myscene.addItem(ResizeHandle()) myview.setScene(myscene) myview.show() app.exec_()
class OWSieveDiagram(OWWidget): """ A two-way contingency table providing information on the relation between the observed and expected frequencies of a combination of values """ name = "Sieve Diagram" icon = "icons/SieveDiagram.svg" priority = 310 inputs = [("Data", Table, "set_data", Default), ("Features", AttributeList, "set_input_features")] outputs = [("Selection", Table)] graph_name = "canvas" want_control_area = False settingsHandler = DomainContextHandler() attrX = ContextSetting("") attrY = ContextSetting("") selection = ContextSetting(set()) def __init__(self): # pylint: disable=missing-docstring super().__init__() self.data = self.discrete_data = None self.attrs = [] self.input_features = None self.areas = [] self.selection = set() self.attr_box = gui.hBox(self.mainArea) model = VariableListModel() model.wrap(self.attrs) combo_args = dict( widget=self.attr_box, master=self, contentsLength=12, callback=self.update_attr, sendSelectedValue=True, valueType=str, model=model) fixed_size = (QSizePolicy.Fixed, QSizePolicy.Fixed) self.attrXCombo = gui.comboBox(value="attrX", **combo_args) gui.widgetLabel(self.attr_box, "\u2715", sizePolicy=fixed_size) self.attrYCombo = gui.comboBox(value="attrY", **combo_args) self.vizrank = SieveRank(self) self.vizrank_button = gui.button( self.attr_box, self, "Score Combinations", sizePolicy=fixed_size, callback=self.vizrank.reshow, enabled=False) self.vizrank.pairSelected.connect(self.set_attr) self.canvas = QGraphicsScene() self.canvasView = ViewWithPress( self.canvas, self.mainArea, handler=self.reset_selection) self.mainArea.layout().addWidget(self.canvasView) self.canvasView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.canvasView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) box = gui.hBox(self.mainArea) box.layout().addWidget(self.graphButton) box.layout().addWidget(self.report_button) def sizeHint(self): return QSize(450, 550) def resizeEvent(self, event): super().resizeEvent(event) self.update_graph() def showEvent(self, event): super().showEvent(event) self.update_graph() def closeEvent(self, event): self.vizrank.close() super().closeEvent(event) def hideEvent(self, event): self.vizrank.hide() super().hideEvent(event) def set_data(self, data): """ Discretize continuous attributes, and put all attributes and discrete metas into self.attrs, which is used as a model for combos. Select the first two attributes unless context overrides this. Method `resolve_shown_attributes` is called to use the attributes from the input, if it exists and matches the attributes in the data. Remove selection; again let the context override this. Initialize the vizrank dialog, but don't show it. Args: data (Table): input data """ if isinstance(data, SqlTable) and data.approx_len() > LARGE_TABLE: data = data.sample_time(DEFAULT_SAMPLE_TIME) self.closeContext() self.data = data self.areas = [] self.selection = set() if self.data is None: self.attrs[:] = [] else: if any(attr.is_continuous for attr in data.domain): discretizer = Discretize( method=EqualFreq(n=4), discretize_classes=True, discretize_metas=True) self.discrete_data = discretizer(data) else: self.discrete_data = self.data self.attrs[:] = [ var for var in chain( self.discrete_data.domain, (var for var in self.data.domain.metas if var.is_discrete)) ] if self.attrs: self.attrX = self.attrs[0].name self.attrY = self.attrs[len(self.attrs) > 1].name else: self.attrX = self.attrY = None self.areas = [] self.selection = set() self.openContext(self.data) self.resolve_shown_attributes() self.update_graph() self.update_selection() self.vizrank.initialize() self.vizrank_button.setEnabled( self.data is not None and len(self.data) > 1 and len(self.data.domain.attributes) > 1) def set_attr(self, attr_x, attr_y): self.attrX, self.attrY = attr_x.name, attr_y.name self.update_attr() def update_attr(self): """Update the graph and selection.""" self.selection = set() self.update_graph() self.update_selection() def set_input_features(self, attr_list): """ Handler for the Features signal. The method stores the attributes and calls `resolve_shown_attributes` Args: attr_list (AttributeList): data from the signal """ self.input_features = attr_list self.resolve_shown_attributes() self.update_selection() def resolve_shown_attributes(self): """ Use the attributes from the input signal if the signal is present and at least two attributes appear in the domain. If there are multiple, use the first two. Combos are disabled if inputs are used. """ self.warning() self.attr_box.setEnabled(True) if not self.input_features: # None or empty return features = [f for f in self.input_features if f in self.attrs] if not features: self.warning( "Features from the input signal are not present in the data") return old_attrs = self.attrX, self.attrY self.attrX, self.attrY = [f.name for f in (features * 2)[:2]] self.attr_box.setEnabled(False) if (self.attrX, self.attrY) != old_attrs: self.selection = set() self.update_graph() def reset_selection(self): self.selection = set() self.update_selection() def select_area(self, area, event): """ Add or remove the clicked area from the selection Args: area (QRect): the area that is clicked event (QEvent): event description """ if event.button() != Qt.LeftButton: return index = self.areas.index(area) if event.modifiers() & Qt.ControlModifier: self.selection ^= {index} else: self.selection = {index} self.update_selection() def update_selection(self): """ Update the graph (pen width) to show the current selection. Filter and output the data. """ if self.areas is None or not self.selection: self.send("Selection", None) return filts = [] for i, area in enumerate(self.areas): if i in self.selection: width = 4 val_x, val_y = area.value_pair filts.append( filter.Values([ filter.FilterDiscrete(self.attrX, [val_x]), filter.FilterDiscrete(self.attrY, [val_y]) ])) else: width = 1 pen = area.pen() pen.setWidth(width) area.setPen(pen) if len(filts) == 1: filts = filts[0] else: filts = filter.Values(filts, conjunction=False) selection = filts(self.discrete_data) if self.discrete_data is not self.data: idset = set(selection.ids) sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset] selection = self.data[sel_idx] self.send("Selection", selection) def update_graph(self): # Function uses weird names like r, g, b, but it does it with utmost # caution, hence # pylint: disable=invalid-name """Update the graph.""" def text(txt, *args, **kwargs): return CanvasText(self.canvas, "", html_text=to_html(txt), *args, **kwargs) def width(txt): return text(txt, 0, 0, show=False).boundingRect().width() def fmt(val): return str(int(val)) if val % 1 == 0 else "{:.2f}".format(val) def show_pearson(rect, pearson, pen_width): """ Color the given rectangle according to its corresponding standardized Pearson residual. Args: rect (QRect): the rectangle being drawn pearson (float): signed standardized pearson residual pen_width (int): pen width (bolder pen is used for selection) """ r = rect.rect() x, y, w, h = r.x(), r.y(), r.width(), r.height() if w == 0 or h == 0: return r = b = 255 if pearson > 0: r = g = max(255 - 20 * pearson, 55) elif pearson < 0: b = g = max(255 + 20 * pearson, 55) else: r = g = b = 224 rect.setBrush(QBrush(QColor(r, g, b))) pen_color = QColor(255 * (r == 255), 255 * (g == 255), 255 * (b == 255)) pen = QPen(pen_color, pen_width) rect.setPen(pen) if pearson > 0: pearson = min(pearson, 10) dist = 20 - 1.6 * pearson else: pearson = max(pearson, -10) dist = 20 - 8 * pearson pen.setWidth(1) def _offseted_line(ax, ay): r = QGraphicsLineItem(x + ax, y + ay, x + (ax or w), y + (ay or h)) self.canvas.addItem(r) r.setPen(pen) ax = dist while ax < w: _offseted_line(ax, 0) ax += dist ay = dist while ay < h: _offseted_line(0, ay) ay += dist def make_tooltip(): """Create the tooltip. The function uses local variables from the enclosing scope.""" # pylint: disable=undefined-loop-variable def _oper(attr_name, txt): if self.data.domain[attr_name] is ddomain[attr_name]: return "=" return " " if txt[0] in "<≥" else " in " return ( "<b>{attrX}{xeq}{xval_name}</b>: {obs_x}/{n} ({p_x:.0f} %)". format(attrX=to_html(attr_x), xeq=_oper(attr_x, xval_name), xval_name=to_html(xval_name), obs_x=fmt(chi.probs_x[x] * n), n=int(n), p_x=100 * chi.probs_x[x]) + "<br/>" + "<b>{attrY}{yeq}{yval_name}</b>: {obs_y}/{n} ({p_y:.0f} %)". format(attrY=to_html(attr_y), yeq=_oper(attr_y, yval_name), yval_name=to_html(yval_name), obs_y=fmt(chi.probs_y[y] * n), n=int(n), p_y=100 * chi.probs_y[y]) + "<hr/>" + """<b>combination of values: </b><br/> expected {exp} ({p_exp:.0f} %)<br/> observed {obs} ({p_obs:.0f} %)""". format(exp=fmt(chi.expected[y, x]), p_exp=100 * chi.expected[y, x] / n, obs=fmt(chi.observed[y, x]), p_obs=100 * chi.observed[y, x] / n)) for item in self.canvas.items(): self.canvas.removeItem(item) if self.data is None or len(self.data) == 0 or \ self.attrX is None or self.attrY is None: return ddomain = self.discrete_data.domain attr_x, attr_y = self.attrX, self.attrY disc_x, disc_y = ddomain[attr_x], ddomain[attr_y] view = self.canvasView chi = ChiSqStats(self.discrete_data, attr_x, attr_y) n = chi.n max_ylabel_w = max((width(val) for val in disc_y.values), default=0) max_ylabel_w = min(max_ylabel_w, 200) x_off = width(attr_x) + max_ylabel_w y_off = 15 square_size = min(view.width() - x_off - 35, view.height() - y_off - 50) square_size = max(square_size, 10) self.canvasView.setSceneRect(0, 0, view.width(), view.height()) curr_x = x_off max_xlabel_h = 0 self.areas = [] for x, (px, xval_name) in enumerate(zip(chi.probs_x, disc_x.values)): if px == 0: continue width = square_size * px curr_y = y_off for y in range(len(chi.probs_y) - 1, -1, -1): # bottom-up order py = chi.probs_y[y] yval_name = disc_y.values[y] if py == 0: continue height = square_size * py selected = len(self.areas) in self.selection rect = CanvasRectangle( self.canvas, curr_x + 2, curr_y + 2, width - 4, height - 4, z=-10, onclick=self.select_area) rect.value_pair = x, y self.areas.append(rect) show_pearson(rect, chi.residuals[y, x], 3 * selected) rect.setToolTip(make_tooltip()) if x == 0: text(yval_name, x_off, curr_y + height / 2, Qt.AlignRight | Qt.AlignVCenter) curr_y += height xl = text(xval_name, curr_x + width / 2, y_off + square_size, Qt.AlignHCenter | Qt.AlignTop) max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h) curr_x += width bottom = y_off + square_size + max_xlabel_h text(attr_y, 0, y_off + square_size / 2, Qt.AlignLeft | Qt.AlignVCenter, bold=True, vertical=True) text(attr_x, x_off + square_size / 2, bottom, Qt.AlignHCenter | Qt.AlignTop, bold=True) xl = text("χ²={:.2f}, p={:.3f}".format(chi.chisq, chi.p), 0, bottom) # Assume similar height for both lines text("N = " + fmt(chi.n), 0, bottom - xl.boundingRect().height()) def get_widget_name_extension(self): if self.data is not None: return "{} vs {}".format(self.attrX, self.attrY) def send_report(self): self.report_plot()
class OWMosaicDisplay(OWWidget): name = "Mosaic Display" description = "Display data in a mosaic plot." icon = "icons/MosaicDisplay.svg" inputs = [("Data", Table, "set_data", Default), ("Data Subset", Table, "set_subset_data")] outputs = [("Selected Data", Table)] settingsHandler = DomainContextHandler() use_boxes = Setting(True) variable1 = ContextSetting("") variable2 = ContextSetting("") variable3 = ContextSetting("") variable4 = ContextSetting("") selection = ContextSetting({}) # interior_coloring is context setting to properly reset it # if the widget switches to regression and back (set setData) interior_coloring = ContextSetting(1) PEARSON, CLASS_DISTRIBUTION = 0, 1 interior_coloring_opts = ["Pearson residuals", "Class distribution"] BAR_WIDTH = 5 SPACING = 4 ATTR_NAME_OFFSET = 20 ATTR_VAL_OFFSET = 3 BLUE_COLORS = [ QColor(255, 255, 255), QColor(210, 210, 255), QColor(110, 110, 255), QColor(0, 0, 255) ] RED_COLORS = [ QColor(255, 255, 255), QColor(255, 200, 200), QColor(255, 100, 100), QColor(255, 0, 0) ] graph_name = "canvas" def __init__(self): super().__init__() self.data = None self.discrete_data = None self.unprocessed_subset_data = None self.subset_data = None self.areas = [] self.canvas = QGraphicsScene() self.canvas_view = ViewWithPress(self.canvas, handler=self.clear_selection) self.mainArea.layout().addWidget(self.canvas_view) self.canvas_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.canvas_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.canvas_view.setRenderHint(QPainter.Antialiasing) box = gui.vBox(self.controlArea, box=True) self.attr_combos = [ gui.comboBox(box, self, value="variable{}".format(i), orientation=Qt.Horizontal, contentsLength=12, callback=self.reset_graph, sendSelectedValue=True, valueType=str) for i in range(1, 5) ] self.rb_colors = gui.radioButtonsInBox(self.controlArea, self, "interior_coloring", self.interior_coloring_opts, box="Interior Coloring", callback=self.update_graph) self.bar_button = gui.checkBox(gui.indentedBox(self.rb_colors), self, 'use_boxes', label='Compare with total', callback=self._compare_with_total) gui.rubber(self.controlArea) def sizeHint(self): return QSize(530, 720) def _compare_with_total(self): if self.data and self.data.domain.has_discrete_class: self.interior_coloring = 1 self.update_graph() def init_combos(self, data): for combo in self.attr_combos: combo.clear() if data is None: return for combo in self.attr_combos[1:]: combo.addItem("(None)") icons = gui.attributeIconDict for attr in chain(data.domain, data.domain.metas): if attr.is_discrete or attr.is_continuous: for combo in self.attr_combos: combo.addItem(icons[attr], attr.name) if self.attr_combos[0].count() > 0: self.variable1 = self.attr_combos[0].itemText(0) self.variable2 = self.attr_combos[1].itemText( 2 * (self.attr_combos[1].count() > 2)) self.variable3 = self.attr_combos[2].itemText(0) self.variable4 = self.attr_combos[3].itemText(0) def get_attr_list(self): return [ a for a in [self.variable1, self.variable2, self.variable3, self.variable4] if a and a != "(None)" ] def resizeEvent(self, e): OWWidget.resizeEvent(self, e) self.update_graph() def showEvent(self, ev): OWWidget.showEvent(self, ev) self.update_graph() def set_data(self, data): if type(data) == SqlTable and data.approx_len() > LARGE_TABLE: data = data.sample_time(DEFAULT_SAMPLE_TIME) self.closeContext() self.data = data self.init_combos(self.data) self.information([0, 1, 2]) if not self.data: self.discrete_data = None return """ TODO: check if data.has_missing_class(): self.information(1, "Examples with missing classes were removed.") """ if any(attr.is_continuous for attr in data.domain): self.discrete_data = Discretize(method=EqualFreq(n=4))(data) else: self.discrete_data = self.data if self.data.domain.class_var is None: self.rb_colors.setDisabled(True) disc_class = False else: self.rb_colors.setDisabled(False) disc_class = self.data.domain.has_discrete_class self.rb_colors.group.button(2).setDisabled(not disc_class) self.bar_button.setDisabled(not disc_class) self.interior_coloring = bool(disc_class) self.openContext(self.data) # if we first received subset we now call setSubsetData to process it if self.unprocessed_subset_data: self.set_subset_data(self.unprocessed_subset_data) self.unprocessed_subset_data = None def set_subset_data(self, data): if self.data is None: self.unprocessed_subset_data = data self.warning(10) return try: self.subset_data = data.from_table(self.data.domain, data) self.warning(10) except: self.subset_data = None self.warning( 10, "'Data' and 'Data Subset' are incompatible" if data is not None else "") # this is called by widget after setData and setSubsetData are called. # this way the graph is updated only once def handleNewSignals(self): self.reset_graph() def clear_selection(self): self.selection = {} self.update_selection_rects() self.send_selection() def reset_graph(self): self.clear_selection() self.update_graph() def update_selection_rects(self): for i, (attr, vals, area) in enumerate(self.areas): if i in self.selection: area.setPen(QPen(Qt.black, 3, Qt.DotLine)) else: area.setPen(QPen()) def select_area(self, index, ev): if ev.button() != Qt.LeftButton: return if ev.modifiers() & Qt.ControlModifier: self.selection ^= {index} else: self.selection = {index} self.update_selection_rects() self.send_selection() def send_selection(self): if not self.selection or self.data is None: self.send("Selected Data", None) return filters = [] self.warning(6) if self.discrete_data is not self.data: if isinstance(self.data, SqlTable): self.warning( 6, "Selection of continuous variables on SQL is not supported" ) for i in self.selection: cols, vals, area = self.areas[i] filters.append( filter.Values( filter.FilterDiscrete(col, [val]) for col, val in zip(cols, vals))) if len(filters) > 1: filters = filter.Values(filters, conjunction=False) else: filters = filters[0] selection = filters(self.discrete_data) if self.discrete_data is not self.data: idset = set(selection.ids) sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset] selection = self.discrete_data[sel_idx] self.send("Selected Data", selection) def send_report(self): self.report_plot(self.canvas) def update_graph(self): spacing = self.SPACING bar_width = self.BAR_WIDTH def draw_data(attr_list, x0_x1, y0_y1, side, condition, total_attrs, used_attrs=[], used_vals=[], attr_vals=""): x0, x1 = x0_x1 y0, y1 = y0_y1 if conditionaldict[attr_vals] == 0: add_rect(x0, x1, y0, y1, "", used_attrs, used_vals, attr_vals=attr_vals) # store coordinates for later drawing of labels draw_text(side, attr_list[0], (x0, x1), (y0, y1), total_attrs, used_attrs, used_vals, attr_vals) return attr = attr_list[0] # how much smaller rectangles do we draw edge = len(attr_list) * spacing values = get_variable_values_sorted(data.domain[attr]) if side % 2: values = values[::-1] # reverse names if necessary if side % 2 == 0: # we are drawing on the x axis # remove the space needed for separating different attr. values whole = max(0, (x1 - x0) - edge * (len(values) - 1)) if whole == 0: edge = (x1 - x0) / float(len(values) - 1) else: # we are drawing on the y axis whole = max(0, (y1 - y0) - edge * (len(values) - 1)) if whole == 0: edge = (y1 - y0) / float(len(values) - 1) if attr_vals == "": counts = [conditionaldict[val] for val in values] else: counts = [ conditionaldict[attr_vals + "-" + val] for val in values ] total = sum(counts) # if we are visualizing the third attribute and the first attribute # has the last value, we have to reverse the order in which the # boxes will be drawn otherwise, if the last cell, nearest to the # labels of the fourth attribute, is empty, we wouldn't be able to # position the labels valrange = list(range(len(values))) if len(attr_list + used_attrs) == 4 and len(used_attrs) == 2: attr1values = get_variable_values_sorted( data.domain[used_attrs[0]]) if used_vals[0] == attr1values[-1]: valrange = valrange[::-1] for i in valrange: start = i * edge + whole * float(sum(counts[:i]) / total) end = i * edge + whole * float(sum(counts[:i + 1]) / total) val = values[i] htmlval = getHtmlCompatibleString(val) if attr_vals != "": newattrvals = attr_vals + "-" + val else: newattrvals = val tooltip = condition + 4 * " " + attr + \ ": <b>" + htmlval + "</b><br>" attrs = used_attrs + [attr] vals = used_vals + [val] common_args = attrs, vals, newattrvals if side % 2 == 0: # if we are moving horizontally if len(attr_list) == 1: add_rect(x0 + start, x0 + end, y0, y1, tooltip, *common_args) else: draw_data(attr_list[1:], (x0 + start, x0 + end), (y0, y1), side + 1, tooltip, total_attrs, *common_args) else: if len(attr_list) == 1: add_rect(x0, x1, y0 + start, y0 + end, tooltip, *common_args) else: draw_data(attr_list[1:], (x0, x1), (y0 + start, y0 + end), side + 1, tooltip, total_attrs, *common_args) draw_text(side, attr_list[0], (x0, x1), (y0, y1), total_attrs, used_attrs, used_vals, attr_vals) def draw_text(side, attr, x0_x1, y0_y1, total_attrs, used_attrs, used_vals, attr_vals): x0, x1 = x0_x1 y0, y1 = y0_y1 if side in drawn_sides: return # the text on the right will be drawn when we are processing # visualization of the last value of the first attribute if side == 3: attr1values = \ get_variable_values_sorted(data.domain[used_attrs[0]]) if used_vals[0] != attr1values[-1]: return if not conditionaldict[attr_vals]: if side not in draw_positions: draw_positions[side] = (x0, x1, y0, y1) return else: if side in draw_positions: # restore the positions of attribute values and name (x0, x1, y0, y1) = draw_positions[side] drawn_sides.add(side) values = get_variable_values_sorted(data.domain[attr]) if side % 2: values = values[::-1] spaces = spacing * (total_attrs - side) * (len(values) - 1) width = x1 - x0 - spaces * (side % 2 == 0) height = y1 - y0 - spaces * (side % 2 == 1) # calculate position of first attribute currpos = 0 if attr_vals == "": counts = [conditionaldict.get(val, 1) for val in values] else: counts = [ conditionaldict.get(attr_vals + "-" + val, 1) for val in values ] total = sum(counts) if total == 0: counts = [1] * len(values) total = sum(counts) aligns = [ Qt.AlignTop | Qt.AlignHCenter, Qt.AlignRight | Qt.AlignVCenter, Qt.AlignBottom | Qt.AlignHCenter, Qt.AlignLeft | Qt.AlignVCenter ] align = aligns[side] for i in range(len(values)): val = values[i] perc = counts[i] / float(total) if distributiondict[val] != 0: if side == 0: CanvasText(self.canvas, str(val), x0 + currpos + width * 0.5 * perc, y1 + self.ATTR_VAL_OFFSET, align) elif side == 1: CanvasText(self.canvas, str(val), x0 - self.ATTR_VAL_OFFSET, y0 + currpos + height * 0.5 * perc, align) elif side == 2: CanvasText(self.canvas, str(val), x0 + currpos + width * perc * 0.5, y0 - self.ATTR_VAL_OFFSET, align) else: CanvasText(self.canvas, str(val), x1 + self.ATTR_VAL_OFFSET, y0 + currpos + height * 0.5 * perc, align) if side % 2 == 0: currpos += perc * width + spacing * (total_attrs - side) else: currpos += perc * height + spacing * (total_attrs - side) if side == 0: CanvasText(self.canvas, attr, x0 + (x1 - x0) / 2, y1 + self.ATTR_VAL_OFFSET + self.ATTR_NAME_OFFSET, align, bold=1) elif side == 1: CanvasText(self.canvas, attr, x0 - max_ylabel_w1 - self.ATTR_VAL_OFFSET, y0 + (y1 - y0) / 2, align, bold=1, vertical=True) elif side == 2: CanvasText(self.canvas, attr, x0 + (x1 - x0) / 2, y0 - self.ATTR_VAL_OFFSET - self.ATTR_NAME_OFFSET, align, bold=1) else: CanvasText(self.canvas, attr, x1 + max_ylabel_w2 + self.ATTR_VAL_OFFSET, y0 + (y1 - y0) / 2, align, bold=1, vertical=True) def add_rect(x0, x1, y0, y1, condition="", used_attrs=[], used_vals=[], attr_vals=""): area_index = len(self.areas) if x0 == x1: x1 += 1 if y0 == y1: y1 += 1 # rectangles of width and height 1 are not shown - increase if x1 - x0 + y1 - y0 == 2: y1 += 1 if class_var and class_var.is_discrete: colors = [QColor(*col) for col in class_var.colors] else: colors = None def select_area(_, ev): self.select_area(area_index, ev) def rect(x, y, w, h, z, pen_color=None, brush_color=None, **args): if pen_color is None: return CanvasRectangle(self.canvas, x, y, w, h, z=z, onclick=select_area, **args) if brush_color is None: brush_color = pen_color return CanvasRectangle(self.canvas, x, y, w, h, pen_color, brush_color, z=z, onclick=select_area, **args) def line(x1, y1, x2, y2): r = QGraphicsLineItem(x1, y1, x2, y2, None) self.canvas.addItem(r) r.setPen(QPen(Qt.white, 2)) r.setZValue(30) outer_rect = rect(x0, y0, x1 - x0, y1 - y0, 30) self.areas.append((used_attrs, used_vals, outer_rect)) if not conditionaldict[attr_vals]: return if self.interior_coloring == self.PEARSON: s = sum(apriori_dists[0]) expected = s * reduce( mul, (apriori_dists[i][used_vals[i]] / float(s) for i in range(len(used_vals)))) actual = conditionaldict[attr_vals] pearson = (actual - expected) / sqrt(expected) if pearson == 0: ind = 0 else: ind = max(0, min(int(log(abs(pearson), 2)), 3)) color = [self.RED_COLORS, self.BLUE_COLORS][pearson > 0][ind] rect(x0, y0, x1 - x0, y1 - y0, -20, color) outer_rect.setToolTip( condition + "<hr/>" + "Expected instances: %.1f<br>" "Actual instances: %d<br>" "Standardized (Pearson) residual: %.1f" % (expected, conditionaldict[attr_vals], pearson)) else: cls_values = get_variable_values_sorted(class_var) prior = get_distribution(data, class_var.name) total = 0 for i, value in enumerate(cls_values): val = conditionaldict[attr_vals + "-" + value] if val == 0: continue if i == len(cls_values) - 1: v = y1 - y0 - total else: v = ((y1 - y0) * val) / conditionaldict[attr_vals] rect(x0, y0 + total, x1 - x0, v, -20, colors[i]) total += v if self.use_boxes and \ abs(x1 - x0) > bar_width and \ abs(y1 - y0) > bar_width: total = 0 line(x0 + bar_width, y0, x0 + bar_width, y1) n = sum(prior) for i, (val, color) in enumerate(zip(prior, colors)): if i == len(prior) - 1: h = y1 - y0 - total else: h = (y1 - y0) * val / n rect(x0, y0 + total, bar_width, h, 20, color) total += h if conditionalsubsetdict: if conditionalsubsetdict[attr_vals]: counts = [ conditionalsubsetdict[attr_vals + "-" + val] for val in cls_values ] if sum(counts) == 1: rect(x0 - 2, y0 - 2, x1 - x0 + 5, y1 - y0 + 5, -550, colors[counts.index(1)], Qt.white, penWidth=2, penStyle=Qt.DashLine) if self.subset_data is not None: line(x1 - bar_width, y0, x1 - bar_width, y1) total = 0 n = conditionalsubsetdict[attr_vals] if n: for i, (cls, color) in \ enumerate(zip(cls_values, colors)): val = conditionalsubsetdict[attr_vals + "-" + cls] if val == 0: continue if i == len(prior) - 1: v = y1 - y0 - total else: v = ((y1 - y0) * val) / n rect(x1 - bar_width, y0 + total, bar_width, v, 15, color) total += v actual = [ conditionaldict[attr_vals + "-" + cls_values[i]] for i in range(len(prior)) ] n_actual = sum(actual) if n_actual > 0: apriori = [prior[key] for key in cls_values] n_apriori = sum(apriori) text = "<br/>".join( "<b>%s</b>: %d / %.1f%% (Expected %.1f / %.1f%%)" % (cls, act, 100.0 * act / n_actual, apr / n_apriori * n_actual, 100.0 * apr / n_apriori) for cls, act, apr in zip(cls_values, actual, apriori)) else: text = "" outer_rect.setToolTip("{}<hr>Instances: {}<br><br>{}".format( condition, n_actual, text[:-4])) def draw_legend(x0_x1, y0_y1): x0, x1 = x0_x1 y0, y1 = y0_y1 if self.interior_coloring == self.PEARSON: names = [ "<-8", "-8:-4", "-4:-2", "-2:2", "2:4", "4:8", ">8", "Residuals:" ] colors = self.RED_COLORS[::-1] + self.BLUE_COLORS[1:] else: names = get_variable_values_sorted(class_var) + \ [class_var.name + ":"] colors = [QColor(*col) for col in class_var.colors] names = [ CanvasText(self.canvas, name, alignment=Qt.AlignVCenter) for name in names ] totalwidth = sum(text.boundingRect().width() for text in names) # compute the x position of the center of the legend y = y1 + self.ATTR_NAME_OFFSET + self.ATTR_VAL_OFFSET + 35 distance = 30 startx = (x0 + x1) / 2 - (totalwidth + (len(names)) * distance) / 2 names[-1].setPos(startx + 15, y) names[-1].show() xoffset = names[-1].boundingRect().width() + distance size = 8 for i in range(len(names) - 1): if self.interior_coloring == self.PEARSON: edgecolor = Qt.black else: edgecolor = colors[i] CanvasRectangle(self.canvas, startx + xoffset, y - size / 2, size, size, edgecolor, colors[i]) names[i].setPos(startx + xoffset + 10, y) xoffset += distance + names[i].boundingRect().width() self.canvas.clear() self.areas = [] data = self.discrete_data if data is None: return subset = self.subset_data attr_list = self.get_attr_list() class_var = data.domain.class_var if class_var: sql = type(data) == SqlTable name = not sql and data.name # save class_var because it is removed in the next line data = data[:, attr_list + [class_var]] data.domain.class_var = class_var if not sql: data.name = name else: data = data[:, attr_list] # TODO: check this # data = Preprocessor_dropMissing(data) if len(data) == 0: self.warning(5, "No valid data for current attributes.") return else: self.warning(5) if self.interior_coloring == self.PEARSON: apriori_dists = [ get_distribution(data, attr) for attr in attr_list ] else: apriori_dists = [] def get_max_label_width(attr): values = get_variable_values_sorted(data.domain[attr]) maxw = 0 for val in values: t = CanvasText(self.canvas, val, 0, 0, bold=0, show=False) maxw = max(int(t.boundingRect().width()), maxw) return maxw # get the maximum width of rectangle xoff = 20 width = 20 if len(attr_list) > 1: text = CanvasText(self.canvas, attr_list[1], bold=1, show=0) max_ylabel_w1 = min(get_max_label_width(attr_list[1]), 150) width = 5 + text.boundingRect().height() + \ self.ATTR_VAL_OFFSET + max_ylabel_w1 xoff = width if len(attr_list) == 4: text = CanvasText(self.canvas, attr_list[3], bold=1, show=0) max_ylabel_w2 = min(get_max_label_width(attr_list[3]), 150) width += text.boundingRect().height() + \ self.ATTR_VAL_OFFSET + max_ylabel_w2 - 10 # get the maximum height of rectangle height = 100 yoff = 45 square_size = min(self.canvas_view.width() - width - 20, self.canvas_view.height() - height - 20) if square_size < 0: return # canvas is too small to draw rectangles self.canvas_view.setSceneRect(0, 0, self.canvas_view.width(), self.canvas_view.height()) drawn_sides = set() draw_positions = {} conditionaldict, distributiondict = \ get_conditional_distribution(data, attr_list) conditionalsubsetdict = None if subset: conditionalsubsetdict, _ = \ get_conditional_distribution(subset, attr_list) # draw rectangles draw_data(attr_list, (xoff, xoff + square_size), (yoff, yoff + square_size), 0, "", len(attr_list)) draw_legend((xoff, xoff + square_size), (yoff, yoff + square_size)) self.update_selection_rects()
class OWVennDiagram(widget.OWWidget): name = "Venn Diagram" icon = "icons/VennDiagram.svg" inputs = [("Data", Orange.data.Table, "setData", widget.Multiple)] outputs = [("Data", Orange.data.Table)] # Selected disjoint subset indices selection = settings.Setting([]) #: Stored input set hints #: {(index, inputname, attributes): (selectedattrname, itemsettitle)} #: The 'selectedattrname' can be None inputhints = settings.Setting({}) #: Use identifier columns for instance matching useidentifiers = settings.Setting(True) autocommit = settings.Setting(False) def __init__(self, parent=None): super().__init__(parent) # Output changed flag self._changed = False # Diagram update is in progress self._updating = False # Input update is in progress self._inputUpdate = False # All input tables have the same domain. self.samedomain = True # Input datasets in the order they were 'connected'. self.data = OrderedDict() # Extracted input item sets in the order they were 'connected' self.itemsets = OrderedDict() # GUI box = gui.widgetBox(self.controlArea, "Info") self.info = gui.widgetLabel(box, "No data on input\n") self.identifiersBox = gui.radioButtonsInBox( self.controlArea, self, "useidentifiers", [], box="Data Instance Identifiers", callback=self._on_useidentifiersChanged) self.useequalityButton = gui.appendRadioButton( self.identifiersBox, "Use instance equality") rb = gui.appendRadioButton(self.identifiersBox, "Use identifiers") self.inputsBox = gui.indentedBox(self.identifiersBox, sep=gui.checkButtonOffsetHint(rb)) self.inputsBox.setEnabled(bool(self.useidentifiers)) for i in range(5): box = gui.widgetBox(self.inputsBox, "Data set #%i" % (i + 1), addSpace=False) box.setFlat(True) model = itemmodels.VariableListModel(parent=self) cb = QComboBox() cb.setModel(model) cb.activated[int].connect(self._on_inputAttrActivated) box.setEnabled(False) # Store the combo in the box for later use. box.combo_box = cb box.layout().addWidget(cb) gui.rubber(self.controlArea) box = gui.widgetBox(self.controlArea, "Output") cb = gui.checkBox(box, self, "autocommit", "Commit on any change") b = gui.button(box, self, "Commit", callback=self.commit, default=True) gui.setStopper(self, b, cb, "_changed", callback=self.commit) # Main area view self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setRenderHint(QPainter.Antialiasing) self.view.setBackgroundRole(QPalette.Window) self.view.setFrameStyle(QGraphicsView.StyledPanel) self.mainArea.layout().addWidget(self.view) self.vennwidget = VennDiagram() self.vennwidget.resize(400, 400) self.vennwidget.itemTextEdited.connect(self._on_itemTextEdited) self.scene.selectionChanged.connect(self._on_selectionChanged) self.scene.addItem(self.vennwidget) self.resize(self.controlArea.sizeHint().width() + 550, max(self.controlArea.sizeHint().height(), 550)) self._queue = [] def setData(self, data, key=None): self.error(0) if not self._inputUpdate: # Store hints only on the first setData call. self._storeHints() self._inputUpdate = True if key in self.data: if data is None: # Remove the input self._remove(key) else: # Update existing item self._update(key, data) elif data is not None: # TODO: Allow setting more them 5 inputs and let the user # select the 5 to display. if len(self.data) == 5: self.error(0, "Can only take 5 inputs.") return # Add a new input self._add(key, data) def handleNewSignals(self): self._inputUpdate = False # Check if all inputs are from the same domain. domains = [input.table.domain for input in self.data.values()] samedomain = all(domain_eq(d1, d2) for d1, d2 in pairwise(domains)) self.useequalityButton.setEnabled(samedomain) self.samedomain = samedomain has_identifiers = all( source_attributes(input.table.domain) for input in self.data.values()) if not samedomain and not self.useidentifiers: self.useidentifiers = 1 elif samedomain and not has_identifiers: self.useidentifiers = 0 incremental = all(inc for _, inc in self._queue) if incremental: # Only received updated data on existing link. self._updateItemsets() else: # Links were removed and/or added. self._createItemsets() self._restoreHints() self._updateItemsets() del self._queue[:] self._createDiagram() if self.data: self.info.setText("{} data sets on input.\n".format(len( self.data))) else: self.info.setText("No data on input\n") self._updateInfo() super().handleNewSignals() def _invalidate(self, keys=None, incremental=True): """ Invalidate input for a list of input keys. """ if keys is None: keys = list(self.data.keys()) self._queue.extend((key, incremental) for key in keys) def itemsetAttr(self, key): index = list(self.data.keys()).index(key) _, combo = self._controlAtIndex(index) model = combo.model() attr_index = combo.currentIndex() if attr_index >= 0: return model[attr_index] else: return None def _controlAtIndex(self, index): group_box = self.inputsBox.layout().itemAt(index).widget() combo = group_box.combo_box return group_box, combo def _setAttributes(self, index, attrs): box, combo = self._controlAtIndex(index) model = combo.model() if attrs is None: model[:] = [] box.setEnabled(False) else: if model[:] != attrs: model[:] = attrs box.setEnabled(True) def _add(self, key, table): name = table.name index = len(self.data) attrs = source_attributes(table.domain) self.data[key] = _InputData(key, name, table) self._setAttributes(index, attrs) self._invalidate([key], incremental=False) item = self.inputsBox.layout().itemAt(index) box = item.widget() box.setTitle("Data set: {}".format(name)) def _remove(self, key): index = list(self.data.keys()).index(key) # Clear possible warnings. self.warning(index) self._setAttributes(index, None) del self.data[key] layout = self.inputsBox.layout() item = layout.takeAt(index) layout.addItem(item) inputs = list(self.data.values()) for i in range(5): box, _ = self._controlAtIndex(i) if i < len(inputs): title = "Data set: {}".format(inputs[i].name) else: title = "Data set #{}".format(i + 1) box.setTitle(title) self._invalidate([key], incremental=False) def _update(self, key, table): name = table.name index = list(self.data.keys()).index(key) attrs = source_attributes(table.domain) self.data[key] = self.data[key]._replace(name=name, table=table) self._setAttributes(index, attrs) self._invalidate([key]) item = self.inputsBox.layout().itemAt(index) box = item.widget() box.setTitle("Data set: {}".format(name)) def _itemsForInput(self, key): useidentifiers = self.useidentifiers or not self.samedomain def items_by_key(key, input): attr = self.itemsetAttr(key) if attr is not None: return [ str(inst[attr]) for inst in input.table if not numpy.isnan(inst[attr]) ] else: return [] def items_by_eq(key, input): return list(map(ComparableInstance, input.table)) input = self.data[key] if useidentifiers: items = items_by_key(key, input) else: items = items_by_eq(key, input) return items def _updateItemsets(self): assert list(self.data.keys()) == list(self.itemsets.keys()) for key, input in list(self.data.items()): items = self._itemsForInput(key) item = self.itemsets[key] item = item._replace(items=items) name = input.name if item.name != name: item = item._replace(name=name, title=name) self.itemsets[key] = item def _createItemsets(self): olditemsets = dict(self.itemsets) self.itemsets.clear() for key, input in self.data.items(): items = self._itemsForInput(key) name = input.name if key in olditemsets and olditemsets[key].name == name: # Reuse the title (which might have been changed by the user) title = olditemsets[key].title else: title = name itemset = _ItemSet(key=key, name=name, title=title, items=items) self.itemsets[key] = itemset def _storeHints(self): if self.data: self.inputhints.clear() for i, (key, input) in enumerate(self.data.items()): attrs = source_attributes(input.table.domain) attrs = tuple(attr.name for attr in attrs) selected = self.itemsetAttr(key) if selected is not None: attr_name = selected.name else: attr_name = None itemset = self.itemsets[key] self.inputhints[(i, input.name, attrs)] = \ (attr_name, itemset.title) def _restoreHints(self): settings = [] for i, (key, input) in enumerate(self.data.items()): attrs = source_attributes(input.table.domain) attrs = tuple(attr.name for attr in attrs) hint = self.inputhints.get((i, input.name, attrs), None) if hint is not None: attr, name = hint attr_ind = attrs.index(attr) if attr is not None else -1 settings.append((attr_ind, name)) else: return # all inputs match the stored hints for i, key in enumerate(self.itemsets): attr, itemtitle = settings[i] self.itemsets[key] = self.itemsets[key]._replace(title=itemtitle) _, cb = self._controlAtIndex(i) cb.setCurrentIndex(attr) def _createDiagram(self): self._updating = True oldselection = list(self.selection) self.vennwidget.clear() n = len(self.itemsets) self.disjoint = disjoint(set(s.items) for s in self.itemsets.values()) vennitems = [] colors = colorpalette.ColorPaletteHSV(n) for i, (key, item) in enumerate(self.itemsets.items()): gr = VennSetItem(text=item.title, count=len(item.items)) color = colors[i] color.setAlpha(100) gr.setBrush(QBrush(color)) gr.setPen(QPen(Qt.NoPen)) vennitems.append(gr) self.vennwidget.setItems(vennitems) for i, area in enumerate(self.vennwidget.vennareas()): area_items = list(map(str, list(self.disjoint[i]))) if i: area.setText("{0}".format(len(area_items))) label = disjoint_set_label(i, n, simplify=False) head = "<h4>|{}| = {}</h4>".format(label, len(area_items)) if len(area_items) > 32: items_str = ", ".join(map(escape, area_items[:32])) hidden = len(area_items) - 32 tooltip = ( "{}<span>{}, ...</br>({} items not shown)<span>".format( head, items_str, hidden)) elif area_items: tooltip = "{}<span>{}</span>".format( head, ", ".join(map(escape, area_items))) else: tooltip = head area.setToolTip(tooltip) area.setPen(QPen(QColor(10, 10, 10, 200), 1.5)) area.setFlag(QGraphicsPathItem.ItemIsSelectable, True) area.setSelected(i in oldselection) self._updating = False self._on_selectionChanged() def _updateInfo(self): # Clear all warnings self.warning(list(range(5))) if not len(self.data): self.info.setText("No data on input\n") else: self.info.setText("{0} data sets on input\n".format(len( self.data))) if self.useidentifiers: for i, key in enumerate(self.data): if not source_attributes(self.data[key].table.domain): self.warning( i, "Data set #{} has no suitable identifiers.".format(i + 1)) def _on_selectionChanged(self): if self._updating: return areas = self.vennwidget.vennareas() indices = [i for i, area in enumerate(areas) if area.isSelected()] self.selection = indices self.invalidateOutput() def _on_useidentifiersChanged(self): self.inputsBox.setEnabled(self.useidentifiers == 1) # Invalidate all itemsets self._invalidate() self._updateItemsets() self._createDiagram() self._updateInfo() def _on_inputAttrActivated(self, attr_index): combo = self.sender() # Find the input index to which the combo box belongs # (they are reordered when removing inputs). index = None inputs = list(self.data.items()) for i in range(len(inputs)): _, c = self._controlAtIndex(i) if c is combo: index = i break assert (index is not None) key, _ = inputs[index] self._invalidate([key]) self._updateItemsets() self._createDiagram() def _on_itemTextEdited(self, index, text): text = str(text) key = list(self.itemsets.keys())[index] self.itemsets[key] = self.itemsets[key]._replace(title=text) def invalidateOutput(self): if self.autocommit: self.commit() else: self._changed = True def commit(self): selected_subsets = [] selected_items = reduce( set.union, [self.disjoint[index] for index in self.selection], set()) def match(val): if numpy.isnan(val): return False else: return str(val) in selected_items source_var = Orange.data.StringVariable("source") item_id_var = Orange.data.StringVariable("item_id") names = [itemset.title.strip() for itemset in self.itemsets.values()] names = uniquify(names) for i, (key, input) in enumerate(self.data.items()): if self.useidentifiers: attr = self.itemsetAttr(key) if attr is not None: mask = list( map(match, (inst[attr] for inst in input.table))) else: mask = [False] * len(input.table) def instance_key(inst): return str(inst[attr]) else: mask = [ ComparableInstance(inst) in selected_items for inst in input.table ] _map = {item: str(i) for i, item in enumerate(selected_items)} def instance_key(inst): return _map[ComparableInstance(inst)] mask = numpy.array(mask, dtype=bool) subset = Orange.data.Table(input.table.domain, input.table[mask]) if len(subset) == 0: continue # add columns with source table id and set id id_column = [[instance_key(inst)] for inst in subset] source_names = numpy.array([[names[i]]] * len(subset)) subset = append_column(subset, "M", source_var, source_names) subset = append_column(subset, "M", item_id_var, id_column) selected_subsets.append(subset) if selected_subsets: data = table_concat(selected_subsets) # Get all variables which are not constant between the same # item set varying = varying_between(data, [item_id_var]) if source_var in varying: varying.remove(source_var) data = reshape_wide(data, varying, [item_id_var], [source_var]) # remove the temporary item set id column data = drop_columns(data, [item_id_var]) else: data = None self.send("Data", data) def getSettings(self, *args, **kwargs): self._storeHints() return super().getSettings(self, *args, **kwargs)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not (self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b - 1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b + 1) def setBrushColor(self, color): self.drawColor = color self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert (self.pos == pos) self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001)) # move a little # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage. # We seem to get better results if we do the following: # 1) Slightly offset the source window because apparently there is a small shift in the data # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x) # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image, # applying some threshold to determine if the final pixel is on or off. tempi = QImage(QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) # Offset the source window. At first I thought the right offset was 0.5, because # that would seem to make sure points are rounded to pixel CENTERS, but # experimentation indicates that 0.25 is slightly better for some reason... source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height())) target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height())) self.scene.render(painter, target=target_rect, source=source_rect) painter.end() # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int) ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr //= 4 * 4 downsample_threshold = (7. / 16) * 255 labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0, 1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero( labels) == 0: labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x, y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen( QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x - self.brushSize // 2 - 1))) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1))) self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1))) self.bb.setBottom( max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1))) #update/move position self.pos = pos
class FlowChartView(QWidget): """ Flowchart view """ def __init__(self, parent): """ Constructs FlowChartView widget @param parent: @type parent: """ QWidget.__init__(self, parent) self.steps = [] self.timestamps = [] self.arrows = [] self.createWidget() def createWidget(self): """ Create the widget """ self.diagramScene = QGraphicsScene(self) self.view = QGraphicsView(self.diagramScene) self.view.setRenderHint(QPainter.Antialiasing) # set the main layout layout = QVBoxLayout() self.logEdit = QTextEdit() self.logEdit.setReadOnly(True) hSplitter2 = QSplitter(self) hSplitter2.setOrientation(Qt.Vertical) hSplitter2.addWidget(self.view) hSplitter2.addWidget(self.logEdit) hSplitter2.setStretchFactor(0, 1) layout.addWidget(hSplitter2) self.setLayout(layout) def reset(self): """ Clear all """ #self.diagramScene.clear() for stp in self.steps: self.diagramScene.removeItem(stp) for stp in self.arrows: self.diagramScene.removeItem(stp) for stamp in self.timestamps: self.diagramScene.removeItem(stamp) self.diagramScene.clear() self.diagramScene.update() self.view.resetCachedContent() self.steps = [] self.arrows = [] self.timestamps = [] self.logEdit.setText("") def addStep(self, text, color="#A5A2A5", width=400, height=40, data=None, textBold=False, textItalic=False, timestamp="00:00:00"): """ Add step """ # take the last one if len(self.steps): latestBlock = self.steps[-1:][0] else: latestBlock = None newBlock = BlockItem(self, text, blockColor=color, width=width, height=height, data=data, bold=textBold, italic=textItalic) if width == 100: newBlock.setPos(400 / 2 - 100 / 2, len(self.steps) * 80) elif width == 300: newBlock.setPos(400 / 2 - 300 / 2, len(self.steps) * 80) else: newBlock.setPos(0, len(self.steps) * 80) self.steps.append(newBlock) self.diagramScene.addItem(newBlock) newTimestampBlock = TimestampItem(self, timestamp) newTimestampBlock.setPos(-200, len(self.timestamps) * 80) self.timestamps.append(newTimestampBlock) self.diagramScene.addItem(newTimestampBlock) if latestBlock is not None: newArrow = LineItem(latestBlock, newBlock) self.diagramScene.addItem(newArrow) self.arrows.append(newArrow) if QtHelper.str2bool(Settings.instance().readValue( key='TestRun/auto-scrolling-graph')): self.view.centerOn(newBlock) return newBlock
class QPokerWidget(QWidget): def __init__(self, dataDir="", parent=None): QWidget.__init__(self, parent) self.renderer = QSvgRenderer(dataDir + "poker.svg") self.scene = QGraphicsScene() self.chat = QGraphicsSimpleTextItem() self.table = QGraphicsSvgItem(dataDir + "poker.svg") self.table.setSharedRenderer(self.renderer) self.table.setElementId("table") self.table.setMatrix(self.renderer.matrixForElement("transform_table")) self.scene.addItem(self.chat) self.scene.addItem(self.table) self.board = [] for i in range(5): card = AnimatedGraphicsSvgItem(dataDir + "svg-cards.svg", self.table) card.setElementId("back") parent = self.renderer.matrixForElement("transform_table") child = self.renderer.matrixForElement("transform_card%i" % i) cardMatrix = child.translate(-parent.dx(), -parent.dy()) card.setMatrix(cardMatrix) #card.setFlag(QGraphicsSvgItem.ItemIsMovable, True) card.scale(0.5, 0.5) card.hide() self.scene.addItem(card) self.board.append(card) self.seats = [] self.names = [] self.moneys = [] self.bets = [] for i in range(10): seat = SeatItem() def seatClickedEvent(seat=i): seatClickedCallback = self.seatClicked seatClickedCallback(seat) seat.event = seatClickedEvent seat.setSharedRenderer(self.renderer) seat.setElementId("seat") seat.setMatrix( self.renderer.matrixForElement("transform_seat%i" % i)) self.scene.addItem(seat) self.seats.append(seat) name = QGraphicsSimpleTextItem(seat) name.setMatrix(self.renderer.matrixForElement("seat_name")) self.scene.addItem(name) self.names.append(name) money = QGraphicsSimpleTextItem(seat) money.setMatrix(self.renderer.matrixForElement("seat_money")) self.scene.addItem(money) self.moneys.append(money) bet = QGraphicsSimpleTextItem() bet.setMatrix(self.renderer.matrixForElement("transform_bet%i" % i)) self.scene.addItem(bet) self.bets.append(bet) self.pots = [] for i in range(9): pot = QGraphicsSimpleTextItem() pot.setMatrix(self.renderer.matrixForElement("transform_pot%i" % i)) self.scene.addItem(pot) self.pots.append(pot) self.view = QGraphicsView(self) self.view.setScene(self.scene) self.view.resize(800, 600) self.fold = ActionItem() self.fold.setText("fold") self.fold.setPos(0, 550) self.scene.addItem(self.fold) self.fold.event = lambda: self.foldClicked() self.check = ActionItem() self.check.setText("check") self.check.setPos(50, 550) self.scene.addItem(self.check) self.check.event = lambda: self.checkClicked() self.call = ActionItem() self.call.setText("call") self.call.setPos(100, 550) self.scene.addItem(self.call) self.call.event = lambda: self.callClicked() self.bet = ActionItem() self.bet.setText("bet") self.bet.setPos(150, 550) self.scene.addItem(self.bet) self.bet.event = lambda: self.betClicked() def renderChat(self, message): self.chat.setText(message) def renderBoard(self, cards): for i in range(len(cards)): item = self.board[i] card = cards[i] item.setElementId(card2SvgElement(card)) if item.isVisible() == False: item.show() for i in range(len(cards), len(self.board)): item = self.board[i] item.hide() item.setElementId('back') def renderStart(self): map(lambda svgItem: svgItem.setElementId('back'), self.board) map(lambda svgItem: svgItem.hide(), self.board) def renderPlayerArrive(self, seat, name): self.names[seat].setText(name) self.names[seat].show() def renderPlayerLeave(self, seat): self.names[seat].setText('') self.names[seat].hide() self.moneys[seat].hide() self.bets[seat].hide() def renderPlayerChips(self, seat, money, bet): if bet > 0: self.bets[seat].setText(str(bet)) self.bets[seat].show() else: self.bets[seat].hide() self.moneys[seat].setText(str(money)) self.moneys[seat].show() def renderPot(self, index, amount): self.pots[index].setText(str(amount)) self.pots[index].show() def renderPotReset(self): for pot in self.pots: pot.setText("") pot.hide() def renderPosition(self, seatInPosition): for i in range(len(self.seats)): seat = self.seats[i] if i == seatInPosition: seat.setElementId("seat_inposition") else: seat.setElementId("seat") def renderPositionReset(self): for seat in self.seats: seat.setElementId("seat") def keyPressEvent(self, event): if event.text() == "q": self.view.scale(1.1, 1.1) elif event.text() == "a": self.view.scale(0.9, 0.9) seatClicked = lambda seat: None foldClicked = lambda: None checkClicked = lambda: None callClicked = lambda: None betClicked = lambda: None
class TakeDragGame(QWidget): def __init__(self, parent=None): super(TakeDragGame, self).__init__(parent) # This is always the same self.dot2 = QGraphicsTextItem(':') self.dot1 = QGraphicsTextItem(':') self.animations = [] self.digits = [] self.main_layout = QHBoxLayout() self.setLayout(self.main_layout) self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 600, 400) self.view = QGraphicsView() self.view.setScene(self.scene) # TODO: Check if its better with opengl or not # self.view.setViewport(QtOpenGL.QGLWidget()) self.main_layout.addWidget(self.view) # self.setWindowState(Qt.WindowMaximized) self.view.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.image_bank = None self.create_and_add_images() # self.scene.setBackgroundBrush(QBrush(Qt.red, Qt.SolidPattern)) # self.populate() # self.animator = QTimer() # self.animator.timeout.connect(self.animate) # self.animate() def create_and_add_images(self): self.load_images_json_file() self.add_background_to_image() self.add_background_from_image() if self.image_bank is not None: for image_id in self.image_bank.keys(): if "clothes" in self.image_bank[image_id]["categories"]: image_path = self.image_bank[image_id]["path"] new_image = DraggableItem(image_path, self.background_from_image) new_image.moved_signal.moved.connect(self.item_moved) self.image_bank[image_id]["widget"] = new_image newpos_x = self.background_from_image.boundingRect().width() / 2 - new_image.boundingRect().width() / 2 newpos_y = self.background_from_image.boundingRect().height() / 2 - new_image.boundingRect().height() / 2 new_image.setPos(newpos_x, newpos_y) # self.scene.addItem(new_image) new_image.setZValue(30) def item_moved(self, pos): widget = self.sender().get_parent() print widget.zValue() print self.background_from_image.zValue() print self.background_to_image.zValue() item_br = widget.sceneBoundingRect() if self.background_from_image.sceneBoundingRect().contains(item_br): widget.setParentItem(self.background_from_image) newpos_x = self.background_from_image.boundingRect().width() / 2 - widget.boundingRect().width() / 2 newpos_y = self.background_from_image.boundingRect().height() / 2 - widget.boundingRect().height() / 2 # self.background_to_image.stackBefore(self.background_from_image) widget.setPos(newpos_x, newpos_y) elif self.background_to_image.sceneBoundingRect().contains(item_br): widget.setParentItem(self.background_to_image) newpos_x = self.background_to_image.boundingRect().width() / 2 - widget.boundingRect().width() / 2 newpos_y = self.background_to_image.boundingRect().height() / 2 - widget.boundingRect().height() / 2 # self.background_from_image.stackBefore(self.background_to_image) widget.setPos(newpos_x, newpos_y) def load_images_json_file(self): with open(os.path.join(CURRENT_PATH, './resources/images.json')) as f: self.image_bank = json.load(f) def add_background_from_image(self, ): assert self.image_bank is not None, "Images need to be loaded before calling this method (try load_images_json_file)" if "Background from" in self.image_bank: background_from_pixmap = QPixmap(self.image_bank["Background from"]["path"]) self.background_from_image = QGraphicsPixmapItem(background_from_pixmap) self.scene.addItem(self.background_from_image) self.background_from_image.setZValue(2) def add_background_to_image(self, ): assert self.image_bank is not None, "Images need to be loaded before calling this method (try load_images_json_file)" if "Background to" in self.image_bank: background_to_pixmap = QPixmap(self.image_bank["Background to"]["path"]) self.background_to_image = QGraphicsPixmapItem(background_to_pixmap) self.scene.addItem(self.background_to_image) self.background_to_image.setZValue(2) def resizeEvent(self, event): view_size = self.view.size() new_background_height = (1.5 / 4.) * view_size.height() background_to_pixmap = QPixmap(self.image_bank["Background to"]["path"]) background_to_pixmap = background_to_pixmap.scaled(new_background_height, new_background_height, Qt.KeepAspectRatio) if not self.background_to_image: self.background_to_image = QGraphicsPixmapItem(background_to_pixmap) else: self.background_to_image.setPixmap(background_to_pixmap) sugested_x_position = int(2 * (view_size.width() / 3.)) if sugested_x_position < 0: sugested_x_position = 0 sugested_y_position = int(view_size.height() / 2. - background_to_pixmap.size().height() / 2) if sugested_y_position < 0: sugested_y_position = 0 self.background_to_image.setPos(sugested_x_position, sugested_y_position) ##################### new_background_height = (2.2 / 4.) * view_size.height() background_from_pixmap = QPixmap(self.image_bank["Background from"]["path"]) background_from_pixmap = background_from_pixmap.scaled(new_background_height, new_background_height, Qt.KeepAspectRatio) if not self.background_to_image: self.background_from_image = QGraphicsPixmapItem(background_from_pixmap) else: self.background_from_image.setPixmap(background_from_pixmap) sugested_x_position = int(view_size.width() / 5. - background_from_pixmap.size().height() / 2) if sugested_x_position < 0: sugested_x_position = 0 sugested_y_position = int(view_size.height() / 2. - background_from_pixmap.size().height() / 2) if sugested_y_position < 0: sugested_y_position = 0 self.background_from_image.setPos(sugested_x_position, sugested_y_position) #### new_widget_height = (1 / 4.) * view_size.height() if self.image_bank is not None: for image_id in self.image_bank.keys(): if "clothes" in self.image_bank[image_id]["categories"]: widget = self.image_bank[image_id]["widget"] pixmap = widget.pixmap pixmap = pixmap.scaled(new_widget_height, new_widget_height, Qt.KeepAspectRatio) widget.setPixmap(pixmap) print widget.moved_flag if not widget.moved_flag: newpos_x = self.background_from_image.boundingRect().width() / 2 - widget.boundingRect().width() / 2 newpos_y = self.background_from_image.boundingRect().height() / 2 - widget.boundingRect().height() / 2 widget.setPos(newpos_x, newpos_y) super(TakeDragGame, self).resizeEvent(event)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not(self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b-1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b+1) def setBrushColor(self, color): self.drawColor = color self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert(self.pos == pos) self.moveTo(QPointF(pos.x()+0.0001, pos.y()+0.0001)) # move a little tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) self.scene.render(painter, target=QRectF(), source=QRectF(QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height()))) painter.end() ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0] labels = numpy.where(ndarr>0,numpy.uint8(self.drawnNumber),numpy.uint8(0)) labels = labels.swapaxes(0,1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0: labels[labels.shape[0]//2, labels.shape[1]//2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x,y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX,oldY), QSize(1,1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x-self.brushSize/2-1) ) ) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0]-1, x+self.brushSize/2+1) ) ) self.bb.setTop( min(self.bb.top(), max(0, y-self.brushSize/2-1) ) ) self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1]-1, y+self.brushSize/2+1) ) ) #update/move position self.pos = pos
class ImagesPreviewer(foundations.ui.common.QWidgetFactory(uiFile=UI_FILE)): """ | This class provides the Application images previewer. | It defines methods to navigate through the list of given images ( List of images paths ), zoom in / out and fit the displayed image, etc... """ def __init__(self, parent, paths=None, *args, **kwargs): """ This method initializes the class. :param parent: Object parent. ( QObject ) :param paths: Images paths. ( Tuple / List ) :param \*args: Arguments. ( \* ) :param \*\*kwargs: Keywords arguments. ( \*\* ) """ LOGGER.debug("> Initializing '{0}()' class.".format( self.__class__.__name__)) super(ImagesPreviewer, self).__init__(parent, *args, **kwargs) # --- Setting class attributes. --- self.__container = parent self.__paths = None self.paths = paths self.__uiResourcesDirectory = "resources" self.__uiResourcesDirectory = os.path.join(os.path.dirname(__file__), self.__uiResourcesDirectory) self.__uiPreviousImage = "Previous.png" self.__uiNextImage = "Next.png" self.__uiZoomOutImage = "Zoom_Out.png" self.__uiZoomInImage = "Zoom_In.png" # Ensure the ui object is destroyed on close to avoid memory leaks. self.setAttribute(Qt.WA_DeleteOnClose) self.__graphicsSceneBackgroundColor = QColor(32, 32, 32) self.__minimumZoomFactor = 0.05 self.__maximumZoomFactor = 25 self.__displayGraphicsItemMargin = 32 self.__graphicsSceneWidth = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).width() * ( 1 / self.__minimumZoomFactor * 1.75) self.__graphicsSceneHeight = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).height() * ( 1 / self.__minimumZoomFactor * 1.75) self.__wheelZoomFactor = 350.0 self.__keyZoomFactor = 1.20 self.__graphicsView = None self.__graphicsScene = None self.__displayGraphicsItem = None ImagesPreviewer.__initializeUi(self) self.loadImage() #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def container(self): """ This method is the property for **self.__container** attribute. :return: self.__container. ( QObject ) """ return self.__container @container.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def container(self, value): """ This method is the setter method for **self.__container** attribute. :param value: Attribute value. ( QObject ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "container")) @container.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def container(self): """ This method is the deleter method for **self.__container** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "container")) @property def paths(self): """ This method is the property for **self.__paths** attribute. :return: self.__paths. ( Tuple / List ) """ return self.__paths @paths.setter @foundations.exceptions.handleExceptions(AssertionError) def paths(self, value): """ This method is the setter method for **self.__paths** attribute. :param value: Attribute value. ( Tuple / List ) """ if value is not None: assert type(value) in ( tuple, list ), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format( "paths", value) for element in value: assert type( element ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "paths", element) self.__paths = value @paths.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def paths(self): """ This method is the deleter method for **self.__paths** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "paths")) @property def uiResourcesDirectory(self): """ This method is the property for **self.__uiResourcesDirectory** attribute. :return: self.__uiResourcesDirectory. ( String ) """ return self.__uiResourcesDirectory @uiResourcesDirectory.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiResourcesDirectory(self, value): """ This method is the setter method for **self.__uiResourcesDirectory** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiResourcesDirectory")) @uiResourcesDirectory.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiResourcesDirectory(self): """ This method is the deleter method for **self.__uiResourcesDirectory** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiResourcesDirectory")) @property def uiPreviousImage(self): """ This method is the property for **self.__uiPreviousImage** attribute. :return: self.__uiPreviousImage. ( String ) """ return self.__uiPreviousImage @uiPreviousImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiPreviousImage(self, value): """ This method is the setter method for **self.__uiPreviousImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiPreviousImage")) @uiPreviousImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiPreviousImage(self): """ This method is the deleter method for **self.__uiPreviousImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiPreviousImage")) @property def uiNextImage(self): """ This method is the property for **self.__uiNextImage** attribute. :return: self.__uiNextImage. ( String ) """ return self.__uiNextImage @uiNextImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiNextImage(self, value): """ This method is the setter method for **self.__uiNextImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiNextImage")) @uiNextImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiNextImage(self): """ This method is the deleter method for **self.__uiNextImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiNextImage")) @property def uiZoomOutImage(self): """ This method is the property for **self.__uiZoomOutImage** attribute. :return: self.__uiZoomOutImage. ( String ) """ return self.__uiZoomOutImage @uiZoomOutImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomOutImage(self, value): """ This method is the setter method for **self.__uiZoomOutImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiZoomOutImage")) @uiZoomOutImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomOutImage(self): """ This method is the deleter method for **self.__uiZoomOutImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiZoomOutImage")) @property def uiZoomInImage(self): """ This method is the property for **self.__uiZoomInImage** attribute. :return: self.__uiZoomInImage. ( String ) """ return self.__uiZoomInImage @uiZoomInImage.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomInImage(self, value): """ This method is the setter method for **self.__uiZoomInImage** attribute. :param value: Attribute value. ( String ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "uiZoomInImage")) @uiZoomInImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiZoomInImage(self): """ This method is the deleter method for **self.__uiZoomInImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiZoomInImage")) @property def graphicsSceneBackgroundColor(self): """ This method is the property for **self.__graphicsSceneBackgroundColor** attribute. :return: self.__graphicsSceneBackgroundColor. ( QColors ) """ return self.__graphicsSceneBackgroundColor @graphicsSceneBackgroundColor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneBackgroundColor(self, value): """ This method is the setter method for **self.__graphicsSceneBackgroundColor** attribute. :param value: Attribute value. ( QColors ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsSceneBackgroundColor")) @graphicsSceneBackgroundColor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneBackgroundColor(self): """ This method is the deleter method for **self.__graphicsSceneBackgroundColor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsSceneBackgroundColor")) @property def graphicsSceneWidth(self): """ This method is the property for **self.__graphicsSceneWidth** attribute. :return: self.__graphicsSceneWidth. ( Integer ) """ return self.__graphicsSceneWidth @graphicsSceneWidth.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneWidth(self, value): """ This method is the setter method for **self.__graphicsSceneWidth** attribute. :param value: Attribute value. ( Integer ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsSceneWidth")) @graphicsSceneWidth.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneWidth(self): """ This method is the deleter method for **self.__graphicsSceneWidth** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsSceneWidth")) @property def graphicsSceneHeight(self): """ This method is the property for **self.__graphicsSceneHeight** attribute. :return: self.__graphicsSceneHeight. ( Object ) """ return self.__graphicsSceneHeight @graphicsSceneHeight.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneHeight(self, value): """ This method is the setter method for **self.__graphicsSceneHeight** attribute. :param value: Attribute value. ( Object ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsSceneHeight")) @graphicsSceneHeight.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsSceneHeight(self): """ This method is the deleter method for **self.__graphicsSceneHeight** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsSceneHeight")) @property def minimumZoomFactor(self): """ This method is the property for **self.__minimumZoomFactor** attribute. :return: self.__minimumZoomFactor. ( Float ) """ return self.__minimumZoomFactor @minimumZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def minimumZoomFactor(self, value): """ This method is the setter method for **self.__minimumZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "minimumZoomFactor")) @minimumZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def minimumZoomFactor(self): """ This method is the deleter method for **self.__minimumZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "minimumZoomFactor")) @property def maximumZoomFactor(self): """ This method is the property for **self.__maximumZoomFactor** attribute. :return: self.__maximumZoomFactor. ( Float ) """ return self.__maximumZoomFactor @maximumZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def maximumZoomFactor(self, value): """ This method is the setter method for **self.__maximumZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "maximumZoomFactor")) @maximumZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def maximumZoomFactor(self): """ This method is the deleter method for **self.__maximumZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "maximumZoomFactor")) @property def wheelZoomFactor(self): """ This method is the property for **self.__wheelZoomFactor** attribute. :return: self.__wheelZoomFactor. ( Float ) """ return self.__wheelZoomFactor @wheelZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def wheelZoomFactor(self, value): """ This method is the setter method for **self.__wheelZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "wheelZoomFactor")) @wheelZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def wheelZoomFactor(self): """ This method is the deleter method for **self.__wheelZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "wheelZoomFactor")) @property def keyZoomFactor(self): """ This method is the property for **self.__keyZoomFactor** attribute. :return: self.__keyZoomFactor. ( Float ) """ return self.__keyZoomFactor @keyZoomFactor.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def keyZoomFactor(self, value): """ This method is the setter method for **self.__keyZoomFactor** attribute. :param value: Attribute value. ( Float ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "keyZoomFactor")) @keyZoomFactor.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def keyZoomFactor(self): """ This method is the deleter method for **self.__keyZoomFactor** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "keyZoomFactor")) @property def graphicsView(self): """ This method is the property for **self.__graphicsView** attribute. :return: self.__graphicsView. ( QGraphicsView ) """ return self.__graphicsView @graphicsView.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsView(self, value): """ This method is the setter method for **self.__graphicsView** attribute. :param value: Attribute value. ( QGraphicsView ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsView")) @graphicsView.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsView(self): """ This method is the deleter method for **self.__graphicsView** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsView")) @property def graphicsScene(self): """ This method is the property for **self.__graphicsScene** attribute. :return: self.__graphicsScene. ( QGraphicsScene ) """ return self.__graphicsScene @graphicsScene.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsScene(self, value): """ This method is the setter method for **self.__graphicsScene** attribute. :param value: Attribute value. ( QGraphicsScene ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "graphicsScene")) @graphicsScene.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def graphicsScene(self): """ This method is the deleter method for **self.__graphicsScene** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "graphicsScene")) @property def displayGraphicsItem(self): """ This method is the property for **self.__displayGraphicsItem** attribute. :return: self.__displayGraphicsItem. ( QGraphicsItem ) """ return self.__displayGraphicsItem @displayGraphicsItem.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def displayGraphicsItem(self, value): """ This method is the setter method for **self.__displayGraphicsItem** attribute. :param value: Attribute value. ( QGraphicsItem ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "displayGraphicsItem")) @displayGraphicsItem.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def displayGraphicsItem(self): """ This method is the deleter method for **self.__displayGraphicsItem** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "displayGraphicsItem")) #****************************************************************************************************************** #*** Class methods. #****************************************************************************************************************** def show(self): """ This method reimplements the :meth:`QWidget.show` method. """ super(ImagesPreviewer, self).show() foundations.ui.common.centerWidgetOnScreen(self) def closeEvent(self, event): """ This method reimplements the :meth:`QWidget.closeEvent` method. :param event: QEvent ( QEvent ) """ LOGGER.debug( "> Removing '{0}' from Images Previewers list.".format(self)) self.__container.imagesPreviewers.remove(self) event.accept() def wheelEvent(self, event): """ This method reimplements the :meth:`QWidget.wheelEvent` method. :param event: QEvent ( QEvent ) """ self.scaleView(pow(1.5, event.delta() / self.__wheelZoomFactor)) def keyPressEvent(self, event): """ This method reimplements the :meth:`QWidget.keyPressEvent` method. :param event: QEvent ( QEvent ) """ key = event.key() if key == Qt.Key_Plus: self.scaleView(self.__keyZoomFactor) elif key == Qt.Key_Minus: self.scaleView(1 / self.__keyZoomFactor) else: super(ImagesPreviewer, self).keyPressEvent(event) def __initializeUi(self): """ This method initializes the Widget ui. """ LOGGER.debug("> Initializing '{0}' ui.".format( self.__class__.__name__)) self.Previous_Image_pushButton.setIcon( QIcon( os.path.join(self.__uiResourcesDirectory, self.__uiPreviousImage))) self.Next_Image_pushButton.setIcon( QIcon(os.path.join(self.__uiResourcesDirectory, self.__uiNextImage))) self.Zoom_In_pushButton.setIcon( QIcon( os.path.join(self.__uiResourcesDirectory, self.__uiZoomInImage))) self.Zoom_Out_pushButton.setIcon( QIcon( os.path.join(self.__uiResourcesDirectory, self.__uiZoomOutImage))) len(self.__paths) <= 1 and self.Navigation_frame.hide() LOGGER.debug("> Initializing graphics View.") self.__graphicsView = QGraphicsView() self.__graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__graphicsView.setTransformationAnchor( QGraphicsView.AnchorUnderMouse) self.__graphicsView.setDragMode(QGraphicsView.ScrollHandDrag) # Reimplementing QGraphicsView wheelEvent method. self.__graphicsView.wheelEvent = self.wheelEvent LOGGER.debug("> Initializing graphics scene.") self.__graphicsScene = QGraphicsScene(self.__graphicsView) self.__graphicsScene.setItemIndexMethod(QGraphicsScene.NoIndex) self.__graphicsScene.setSceneRect( -(float(self.__graphicsSceneWidth)) / 2, -(float(self.__graphicsSceneHeight)) / 2, float(self.__graphicsSceneWidth), float(self.__graphicsSceneHeight)) self.__graphicsView.setScene(self.__graphicsScene) self.__graphicsView.setBackgroundBrush( QBrush(self.__graphicsSceneBackgroundColor)) self.Images_Previewer_frame_gridLayout.addWidget(self.__graphicsView) # Signals / Slots. self.__container.engine.imagesCaches.QImage.contentAdded.connect( self.__engine_imagesCaches_QImage__contentAdded) self.Previous_Image_pushButton.clicked.connect( self.__Previous_Image_pushButton__clicked) self.Next_Image_pushButton.clicked.connect( self.__Next_Image_pushButton__clicked) self.Zoom_Out_pushButton.clicked.connect( self.__Zoom_Out_pushButton__clicked) self.Zoom_In_pushButton.clicked.connect( self.__Zoom_In_pushButton__clicked) self.Zoom_Fit_pushButton.clicked.connect( self.__Zoom_Fit_pushButton__clicked) def __Images_Informations_label_setUi(self): """ This method sets the **Images_Informations_label** Widget ui. """ if not self.__displayGraphicsItem: return image = self.__displayGraphicsItem.image self.Images_Informations_label.setText( "{0} - {1}x{2} px - {3} bit".format( os.path.basename(image.data.path), image.data.width, image.data.height, image.data.bpp / 4)) def __engine_imagesCaches_QImage__contentAdded(self, content): """ This method is triggered by the Application **QImage** images cache when content has been added. :param content: Cache added content. ( List ) """ if not self.__paths: return path = foundations.common.getFirstItem(content) if not path in self.__paths: return image = self.__container.engine.imagesCaches.QImage.getContent(path) self.__setDisplayGraphicsItem(image) def __Previous_Image_pushButton__clicked(self, checked): """ This method is triggered when **Previous_Image_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.loopThroughImages(True) def __Next_Image_pushButton__clicked(self, checked): """ This method is triggered when **Next_Image_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.loopThroughImages() def __Zoom_In_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_In_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.scaleView(self.__keyZoomFactor) def __Zoom_Out_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_Out_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.scaleView(1 / self.__keyZoomFactor) def __Zoom_Fit_pushButton__clicked(self, checked): """ This method is triggered when **Zoom_Fit_pushButton** Widget is clicked. :param checked: Checked state. ( Boolean ) """ self.fitImage() def __clearGraphicsScene(self): """ This method clears the View. """ for graphicsItem in self.__graphicsScene.items(): self.__graphicsScene.removeItem(graphicsItem) def __setDisplayGraphicsItem(self, image): """ This method sets the View using given image. :param image: Image to display. ( Qimage ) """ self.__clearGraphicsScene() LOGGER.debug("> Initializing graphics item.") self.__displayGraphicsItem = Image_QGraphicsItem(image=image) self.__graphicsScene.addItem(self.__displayGraphicsItem) self.__Images_Informations_label_setUi() def loadImage(self, index=0): """ This method loads the display image in the View. :param index: Index to load. ( Integer ) :return: Method success. ( Boolean ) """ if not self.__paths: return False image = sibl_gui.ui.common.getImage(self.__paths[index]) self.__setDisplayGraphicsItem(image) return True def scaleView(self, scaleFactor): """ This method scales the Previewer view. :param scaleFactor: Float ( Float ) :return: Method success. ( Boolean ) """ graphicsView = self.findChild(QGraphicsView) factor = graphicsView.matrix().scale(scaleFactor, scaleFactor).mapRect( QRectF(0, 0, 1, 1)).width() if factor < self.__minimumZoomFactor or factor > self.__maximumZoomFactor: return False graphicsView.scale(scaleFactor, scaleFactor) return True def fitWindow(self): """ This method fits the View window. :return: Method success. ( Boolean ) """ if not self.__displayGraphicsItem: return False desktopWidth = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).width() desktopHeight = QApplication.desktop().screenGeometry( QApplication.desktop().primaryScreen()).height() width = min(desktopWidth * 0.80, self.__displayGraphicsItem.width) height = min(desktopHeight * 0.80, self.__displayGraphicsItem.height) self.resize(width, height) foundations.ui.common.centerWidgetOnScreen(self) return True def fitImage(self): """ This method fits the image to the View. :return: Method success. ( Boolean ) """ if not self.__displayGraphicsItem: return False self.__graphicsView.fitInView( QRectF( -(self.__displayGraphicsItem.width / 2) - (self.__displayGraphicsItemMargin / 2), -(self.__displayGraphicsItem.height / 2) - (self.__displayGraphicsItemMargin / 2), self.__displayGraphicsItem.width + self.__displayGraphicsItemMargin, self.__displayGraphicsItem.height + self.__displayGraphicsItemMargin), Qt.KeepAspectRatio) return True def loopThroughImages(self, backward=False): """ This method loops through View images. :param backward: Looping backward. ( Boolean ) :return: Method success. ( Boolean ) """ index = self.__paths.index(self.__displayGraphicsItem.image.data.path) index += not backward and 1 or -1 if index < 0: index = len(self.__paths) - 1 elif index > len(self.__paths) - 1: index = 0 self.loadImage(index) return True