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 Canvas(QGraphicsView): def __init__(self): self._scene = QGraphicsScene() QGraphicsView.__init__(self, self._scene) self._document = Document() self._document.changed.connect(self._update_scene) self.use_tool(PenTool) self.setMouseTracking(True) def use_tool(self, tool_class): """Instantiates tool_class and uses it as the current tool.""" self._tool = tool_class(self._document) self._tool.needs_repaint.connect(self._update) def new_shape(self): self._document.new_shape() def delete_selection(self): self._document.delete_selection() if not self._document.current_shape: self._document.delete_current_shape() def _update(self): self.update() def _update_scene(self): self._scene.clear() for shape in self._document.shapes: self._scene.addPath(shape.make_painter_path()) def _call_tool(self, method_name, *args): method = getattr(self._tool, method_name, None) if method: method(*args) def _map_event(self, qt_event): """Take a QMouseEvent and return a MouseEvent in scene space.""" point = self.mapToScene(qt_event.x(), qt_event.y()) return MouseEvent((_round_to_half(point.x()), _round_to_half(point.y()))) def mouseMoveEvent(self, event): self._call_tool("mouse_move_event", self._map_event(event)) def mousePressEvent(self, event): self._call_tool("mouse_press_event", self._map_event(event)) def mouseReleaseEvent(self, event): self._call_tool("mouse_release_event", self._map_event(event)) def paintEvent(self, event): QGraphicsView.paintEvent(self, event) self._call_tool("paint_event", self)
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
class TestItems(unittest.TestCase): def setUp(self): import logging from PyQt4.QtGui import QApplication, QGraphicsScene, QGraphicsView, \ QPainter from PyQt4.QtCore import QTimer logging.basicConfig() self.app = QApplication([]) self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setRenderHints( QPainter.Antialiasing | \ QPainter.SmoothPixmapTransform | \ QPainter.TextAntialiasing ) self.view.resize(500, 300) self.view.show() QTimer.singleShot(10000, self.app.exit) def my_excepthook(*args): sys.setrecursionlimit(1010) traceback.print_exc(limit=4) self._orig_excepthook = sys.excepthook sys.excepthook = my_excepthook self.singleShot = QTimer.singleShot def tearDown(self): self.scene.clear() self.scene.deleteLater() self.view.deleteLater() del self.scene del self.view self.app.processEvents() del self.app sys.excepthook = self._orig_excepthook
class TestItems(unittest.TestCase): def setUp(self): import logging from PyQt4.QtGui import QApplication, QGraphicsScene, QGraphicsView, \ QPainter from PyQt4.QtCore import QTimer logging.basicConfig() self.app = QApplication([]) self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.setRenderHints( QPainter.Antialiasing | \ QPainter.SmoothPixmapTransform | \ QPainter.TextAntialiasing ) self.view.resize(500, 300) self.view.show() QTimer.singleShot(10000, self.app.exit) def my_excepthook(etype, value, tb): sys.setrecursionlimit(1010) traceback.print_exception(etype, value, tb) self._orig_excepthook = sys.excepthook sys.excepthook = my_excepthook self.singleShot = QTimer.singleShot def tearDown(self): self.scene.clear() self.scene.deleteLater() self.view.deleteLater() del self.scene del self.view self.app.processEvents() del self.app sys.excepthook = self._orig_excepthook
class OWQualityControl(widget.OWWidget): name = "Quality Control" description = "Experiment quality control" icon = "../widgets/icons/QualityControl.svg" priority = 5000 inputs = [("Experiment Data", Orange.data.Table, "set_data")] outputs = [] DISTANCE_FUNCTIONS = [("Distance from Pearson correlation", dist_pcorr), ("Euclidean distance", dist_eucl), ("Distance from Spearman correlation", dist_spearman) ] settingsHandler = SetContextHandler() split_by_labels = settings.ContextSetting({}) sort_by_labels = settings.ContextSetting({}) selected_distance_index = settings.Setting(0) def __init__(self, parent=None): super().__init__(parent) ## Attributes self.data = None self.distances = None self.groups = None self.unique_pos = None self.base_group_index = 0 ## GUI box = gui.widgetBox(self.controlArea, "Info") self.info_box = gui.widgetLabel(box, "\n") ## Separate By box box = gui.widgetBox(self.controlArea, "Separate By") self.split_by_model = itemmodels.PyListModel(parent=self) self.split_by_view = QListView() self.split_by_view.setSelectionMode(QListView.ExtendedSelection) self.split_by_view.setModel(self.split_by_model) box.layout().addWidget(self.split_by_view) self.split_by_view.selectionModel().selectionChanged.connect( self.on_split_key_changed) ## Sort By box box = gui.widgetBox(self.controlArea, "Sort By") self.sort_by_model = itemmodels.PyListModel(parent=self) self.sort_by_view = QListView() self.sort_by_view.setSelectionMode(QListView.ExtendedSelection) self.sort_by_view.setModel(self.sort_by_model) box.layout().addWidget(self.sort_by_view) self.sort_by_view.selectionModel().selectionChanged.connect( self.on_sort_key_changed) ## Distance box box = gui.widgetBox(self.controlArea, "Distance Measure") gui.comboBox(box, self, "selected_distance_index", items=[name for name, _ in self.DISTANCE_FUNCTIONS], callback=self.on_distance_measure_changed) self.scene = QGraphicsScene() self.scene_view = QGraphicsView(self.scene) self.scene_view.setRenderHints(QPainter.Antialiasing) self.scene_view.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.mainArea.layout().addWidget(self.scene_view) self.scene_view.installEventFilter(self) self._disable_updates = False self._cached_distances = {} self._base_index_hints = {} self.main_widget = None self.resize(800, 600) def clear(self): """Clear the widget state.""" self.data = None self.distances = None self.groups = None self.unique_pos = None with disable_updates(self): self.split_by_model[:] = [] self.sort_by_model[:] = [] self.main_widget = None self.scene.clear() self.info_box.setText("\n") self._cached_distances = {} def set_data(self, data=None): """Set input experiment data.""" self.closeContext() self.clear() self.error(0) self.warning(0) if data is not None: keys = self.get_suitable_keys(data) if not keys: self.error(0, "Data has no suitable feature labels.") data = None self.data = data if data is not None: self.on_new_data() def update_label_candidates(self): """Update the label candidates selection GUI (Group/Sort By views). """ keys = self.get_suitable_keys(self.data) with disable_updates(self): self.split_by_model[:] = keys self.sort_by_model[:] = keys def get_suitable_keys(self, data): """ Return suitable attr label keys from the data where the key has at least two unique values in the data. """ attrs = [attr.attributes.items() for attr in data.domain.attributes] attrs = reduce(operator.iadd, attrs, []) # in case someone put non string values in attributes dict attrs = [(str(key), str(value)) for key, value in attrs] attrs = set(attrs) values = defaultdict(set) for key, value in attrs: values[key].add(value) keys = [key for key in values if len(values[key]) > 1] return keys def selected_split_by_labels(self): """Return the current selected split labels. """ sel_m = self.split_by_view.selectionModel() indices = [r.row() for r in sel_m.selectedRows()] return [self.sort_by_model[i] for i in indices] def selected_sort_by_labels(self): """Return the current selected sort labels """ sel_m = self.sort_by_view.selectionModel() indices = [r.row() for r in sel_m.selectedRows()] return [self.sort_by_model[i] for i in indices] def selected_distance(self): """Return the selected distance function. """ return self.DISTANCE_FUNCTIONS[self.selected_distance_index][1] def selected_base_group_index(self): """Return the selected base group index """ return self.base_group_index def selected_base_indices(self, base_group_index=None): indices = [] for g, ind in self.groups: if base_group_index is None: label = group_label(self.selected_split_by_labels(), g) ind = [i for i in ind if i is not None] i = self._base_index_hints.get(label, ind[0] if ind else None) else: i = ind[base_group_index] indices.append(i) return indices def on_new_data(self): """We have new data and need to recompute all. """ self.closeContext() self.update_label_candidates() self.info_box.setText( "%s genes \n%s experiments" % (len(self.data), len(self.data.domain.attributes))) self.base_group_index = 0 keys = self.get_suitable_keys(self.data) self.openContext(keys) ## Restore saved context settings (split/sort selection) split_by_labels = self.split_by_labels sort_by_labels = self.sort_by_labels def select(model, selection_model, selected_items): """Select items in a Qt item model view """ all_items = list(model) try: indices = [all_items.index(item) for item in selected_items] except: indices = [] for ind in indices: selection_model.select(model.index(ind), QItemSelectionModel.Select) with disable_updates(self): select(self.split_by_view.model(), self.split_by_view.selectionModel(), split_by_labels) select(self.sort_by_view.model(), self.sort_by_view.selectionModel(), sort_by_labels) with widget_disable(self): self.split_and_update() def on_split_key_changed(self, *args): """Split key has changed """ with widget_disable(self): if not self._disable_updates: self.base_group_index = 0 self.split_by_labels = self.selected_split_by_labels() self.split_and_update() def on_sort_key_changed(self, *args): """Sort key has changed """ with widget_disable(self): if not self._disable_updates: self.base_group_index = 0 self.sort_by_labels = self.selected_sort_by_labels() self.split_and_update() def on_distance_measure_changed(self): """Distance measure has changed """ if self.data is not None: with widget_disable(self): self.update_distances() self.replot_experiments() def on_view_resize(self, size): """The view with the quality plot has changed """ if self.main_widget: current = self.main_widget.size() self.main_widget.resize(size.width() - 6, current.height()) self.scene.setSceneRect(self.scene.itemsBoundingRect()) def on_rug_item_clicked(self, item): """An ``item`` in the quality plot has been clicked. """ update = False sort_by_labels = self.selected_sort_by_labels() if sort_by_labels and item.in_group: ## The item is part of the group if item.group_index != self.base_group_index: self.base_group_index = item.group_index update = True else: if sort_by_labels: # If the user clicked on an background item it # invalidates the sorted labels selection with disable_updates(self): self.sort_by_view.selectionModel().clear() update = True index = item.index group = item.group label = group_label(self.selected_split_by_labels(), group) if self._base_index_hints.get(label, 0) != index: self._base_index_hints[label] = index update = True if update: with widget_disable(self): self.split_and_update() def eventFilter(self, obj, event): if obj is self.scene_view and event.type() == QEvent.Resize: self.on_view_resize(event.size()) return super().eventFilter(obj, event) def split_and_update(self): """ Split the data based on the selected sort/split labels and update the quality plot. """ split_labels = self.selected_split_by_labels() sort_labels = self.selected_sort_by_labels() self.warning(0) if not split_labels: self.warning(0, "No separate by label selected.") self.groups, self.unique_pos = \ exp.separate_by(self.data, split_labels, consider=sort_labels, add_empty=True) self.groups = sorted(self.groups.items(), key=lambda t: list(map(float_if_posible, t[0]))) self.unique_pos = sorted( self.unique_pos.items(), key=lambda t: list(map(float_if_posible, t[0]))) if self.groups: if sort_labels: group_base = self.selected_base_group_index() base_indices = self.selected_base_indices(group_base) else: base_indices = self.selected_base_indices() self.update_distances(base_indices) self.replot_experiments() def get_cached_distances(self, measure): if measure not in self._cached_distances: attrs = self.data.domain.attributes mat = numpy.zeros((len(attrs), len(attrs))) self._cached_distances[measure] = \ (mat, set(zip(range(len(attrs)), range(len(attrs))))) return self._cached_distances[measure] def get_cached_distance(self, measure, i, j): matrix, computed = self.get_cached_distances(measure) key = (i, j) if i < j else (j, i) if key in computed: return matrix[i, j] else: return None def get_distance(self, measure, i, j): d = self.get_cached_distance(measure, i, j) if d is None: vec_i = take_columns(self.data, [i]) vec_j = take_columns(self.data, [j]) d = measure(vec_i, vec_j) mat, computed = self.get_cached_distances(measure) mat[i, j] = d key = key = (i, j) if i < j else (j, i) computed.add(key) return d def store_distance(self, measure, i, j, dist): matrix, computed = self.get_cached_distances(measure) key = (i, j) if i < j else (j, i) matrix[j, i] = matrix[i, j] = dist computed.add(key) def update_distances(self, base_indices=()): """Recompute the experiment distances. """ distance = self.selected_distance() if base_indices == (): base_group_index = self.selected_base_group_index() base_indices = [ind[base_group_index] \ for _, ind in self.groups] assert (len(base_indices) == len(self.groups)) base_distances = [] attributes = self.data.domain.attributes pb = gui.ProgressBar(self, len(self.groups) * len(attributes)) for (group, indices), base_index in zip(self.groups, base_indices): # Base column of the group if base_index is not None: base_vec = take_columns(self.data, [base_index]) distances = [] # Compute the distances between base column # and all the rest data columns. for i in range(len(attributes)): if i == base_index: distances.append(0.0) elif self.get_cached_distance(distance, i, base_index) is not None: distances.append( self.get_cached_distance(distance, i, base_index)) else: vec_i = take_columns(self.data, [i]) dist = distance(base_vec, vec_i) self.store_distance(distance, i, base_index, dist) distances.append(dist) pb.advance() base_distances.append(distances) else: base_distances.append(None) pb.finish() self.distances = base_distances def replot_experiments(self): """Replot the whole quality plot. """ self.scene.clear() labels = [] max_dist = numpy.nanmax(list(filter(None, self.distances))) rug_widgets = [] group_pen = QPen(Qt.black) group_pen.setWidth(2) group_pen.setCapStyle(Qt.RoundCap) background_pen = QPen(QColor(0, 0, 250, 150)) background_pen.setWidth(1) background_pen.setCapStyle(Qt.RoundCap) main_widget = QGraphicsWidget() layout = QGraphicsGridLayout() attributes = self.data.domain.attributes if self.data is not None: for (group, indices), dist_vec in zip(self.groups, self.distances): indices_set = set(indices) rug_items = [] if dist_vec is not None: for i, attr in enumerate(attributes): # Is this a within group distance or background in_group = i in indices_set if in_group: rug_item = ClickableRugItem( dist_vec[i] / max_dist, 1.0, self.on_rug_item_clicked) rug_item.setPen(group_pen) tooltip = experiment_description(attr) rug_item.setToolTip(tooltip) rug_item.group_index = indices.index(i) rug_item.setZValue(rug_item.zValue() + 1) else: rug_item = ClickableRugItem( dist_vec[i] / max_dist, 0.85, self.on_rug_item_clicked) rug_item.setPen(background_pen) tooltip = experiment_description(attr) rug_item.setToolTip(tooltip) rug_item.group = group rug_item.index = i rug_item.in_group = in_group rug_items.append(rug_item) rug_widget = RugGraphicsWidget(parent=main_widget) rug_widget.set_rug(rug_items) rug_widgets.append(rug_widget) label = group_label(self.selected_split_by_labels(), group) label_item = QGraphicsSimpleTextItem(label, main_widget) label_item = GraphicsSimpleTextLayoutItem(label_item, parent=layout) label_item.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) labels.append(label_item) for i, (label, rug_w) in enumerate(zip(labels, rug_widgets)): layout.addItem(label, i, 0, Qt.AlignVCenter) layout.addItem(rug_w, i, 1) layout.setRowMaximumHeight(i, 30) main_widget.setLayout(layout) self.scene.addItem(main_widget) self.main_widget = main_widget self.rug_widgets = rug_widgets self.labels = labels self.on_view_resize(self.scene_view.size())
class CoLocation(QMainWindow, Ui_MainWindow): flag = True categories = {} valid_images = ["jpg", "png", "tga", "pgm", "jpeg"] valid_videos = ["mp4", "avi"] edge_threshold = 100 to_disp = [] stop = False framerate = 20 export_name = '' def __init__(self, ): super( CoLocation, self).__init__() #initialise from the ui designed by Designer App self.setupUi(self) self.setupUi_custom() Help = QtGui.QAction(QtGui.QIcon('images/info.png'), 'Help', self) Help.triggered.connect(self.show_help) Settings = QtGui.QAction(QtGui.QIcon('images/settings.png'), 'Settings', self) Settings.triggered.connect(self.show_settings) Export = QtGui.QAction(QtGui.QIcon('images/export.png'), 'Export', self) Export.triggered.connect(self.show_export) ##To set up the toolbar self.toolbar = self.addToolBar('Help') self.toolbar.addAction(Help) self.toolbar = self.addToolBar('Settings') self.toolbar.addAction(Settings) self.toolbar = self.addToolBar('Export') self.toolbar.addAction(Export) def show_help(self): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("Co-Location Visualisation") f = open('How-To/how-to-Co-Location.txt', 'r') msg.setInformativeText( "Developed by Yash Chandak, under supervision of Prof. Babiga Birregah, University of Technology, Troyes" ) msg.setWindowTitle("About Us") msg.setDetailedText(f.read()) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def show_settings(self): framerate, ok = QtGui.QInputDialog.getInt( self, 'Settings', 'Enter Frame Rate for Videos:') self.framerate = framerate def show_export(self): name, ok = QtGui.QInputDialog.getText(self, 'Export to Gephi format', 'Enter file name :') self.export_name = name + '.gefx' def update_categories(self): #update selected categories for radiobox in self.findChildren(QtGui.QRadioButton): self.categories[radiobox.text()] = radiobox.isChecked() def setupUi_custom(self, ): self.scene = QGraphicsScene() self.scene2 = QGraphicsScene() self.pushButton.clicked.connect(self.selectFile) self.horizontalSlider.valueChanged.connect(self.updateLCD) self.pushButton_2.clicked.connect(self.disp_graph) self.pushButton_3.clicked.connect(self.selectFile_from_folder) self.stop_button.clicked.connect(self.set_stop) #TODO [WEIRD PROBLEM] QPixmap needs to be called at least once with JPG image before tensorFlow, otherwise program crashes self.scene.addPixmap( QPixmap(os.getcwd() + "/images/demo.jpg").scaled( self.graphicsView.size(), QtCore.Qt.KeepAspectRatio)) self.graphicsView.setScene(self.scene) #Add blank canvas initially fig1 = Figure() self.addmpl(fig1) def set_stop(self): self.stop = True def updateLCD(self): #update edge_threshold variable based on slider self.edge_threshold = self.horizontalSlider.value() self.lcdNumber.display(self.edge_threshold) def tag_image(self, filename=None, batch=False, image=None): #importing TensorFlow on top causes segmentation fault (official bug #2034) #importing here helps in working around the problem #Python modules could be con)sidered as singletons... so no matter how many times they are imported, they get initialized only once import Yolo_module as yolo if (self.flag): #initialise the model, only once self.classifier = yolo.YOLO_TF() self.flag = False self.classifier.batch = batch if not image == None: self.classifier.detect_from_cvmat(image) else: self.classifier.detect_from_file( filename) #execute Yolo on the image return self.classifier.tagged_image def disp_img(self, filename=None, img=None): if not img == None: img_rgb = img.copy() cv2.cvtColor(img, cv2.COLOR_BGR2RGB, img_rgb) img_rgb = QtGui.QImage(img_rgb, img_rgb.shape[1], img_rgb.shape[0], img_rgb.shape[1] * 3, QtGui.QImage.Format_RGB888) self.scene.addPixmap( QPixmap(img_rgb).scaled(self.graphicsView.size(), QtCore.Qt.KeepAspectRatio)) image = self.tag_image(image=img) else: #DO this step before calling tensorflow self.scene.addPixmap( QPixmap(filename).scaled(self.graphicsView.size(), QtCore.Qt.KeepAspectRatio)) #Dislplay tagged image image = self.tag_image(filename=filename) image = QtGui.QImage( image, image.shape[1], image.shape[0], image.shape[1] * 3, QtGui.QImage.Format_RGB888) #convert to Qt image format self.scene2.addPixmap( QPixmap(image).scaled(self.graphicsView_3.size(), QtCore.Qt.KeepAspectRatio)) self.graphicsView.setScene(self.scene) self.graphicsView_3.setScene(self.scene2) def disp_graph(self, result=[], graph_name=''): import graph_module as gm self.update_categories() self.rmmpl() #remove previous graph if result != [] and result != False: self.to_disp = result #Display graph fig = Figure() fig.set_facecolor('w') axf = fig.add_subplot(111) axf.set_axis_off() gm.co_location(self.to_disp, axf, self.edge_threshold, self.categories, graph_name) #get updated graph self.addmpl(fig) print("graph added") def disp_video(self, filename, skip=20): cap = cv2.VideoCapture(filename) count = 0 self.stop = False while True: #TODO: Better method - https://nikolak.com/pyqt-threading-tutorial/ QtCore.QCoreApplication.processEvents() ret, img = cap.read() if (not ret) or self.stop: print("Ending video...") #+ str(ret) + str(self.stop)) break if count % skip == 0: img = cv2.resize(img, (640, 480)) self.disp_img(img=img) self.disp_graph([self.classifier.result ]) #list of 1 resultant list count = 0 count += 1 def selectFile(self): #Clear previous image displays self.scene.clear() self.scene2.clear() self.update_categories() filename = QFileDialog.getOpenFileName( directory='/home/yash/Downloads/Pascal VOC 2012/samples') self.lineEdit.setText(filename) #check if file is valid video if filename.split('.')[1] in self.valid_videos: self.disp_video(filename, self.framerate) #check if the file is valid elif filename.split('.')[1] in self.valid_images: self.disp_img(filename=filename) self.disp_graph([self.classifier.result ]) #list of 1 resultant list else: print("Invalid file format") def selectFile_from_folder(self): #Read all the images in the folder path = QFileDialog.getExistingDirectory( None, 'Select a folder:', '/home/yash/Downloads/Pascal VOC 2012', QtGui.QFileDialog.ShowDirsOnly) self.lineEdit_2.setText(path) self.batch_results = [] for f in os.listdir(path): #list all the files in the folder ext = f.split('.')[1] #get the file extension if ext.lower( ) not in self.valid_images: #check if the extension is valid for the image continue filename = path + '/' + f #create the path of the image print(filename) self.tag_image(filename, batch=True) self.batch_results.append( self.classifier.result) #list of all resultant lists #clear the image regions during batch upload self.scene.clear() self.scene2.clear() self.disp_graph(self.batch_results, self.export_name) def addmpl(self, fig): #Add figure to canvas and widget self.canvas = FigureCanvas(fig) self.mplvl.addWidget(self.canvas) self.canvas.draw() def rmmpl(self, ): #remove the canvas and widget self.mplvl.removeWidget(self.canvas) self.canvas.close()
class ProfileGraphViewer(QWidget): " Profiling results as a graph " escapePressed = pyqtSignal() def __init__(self, scriptName, params, reportTime, dataFile, stats, parent=None): QWidget.__init__(self, parent) self.__dataFile = dataFile self.__script = scriptName self.__reportTime = reportTime self.__params = params self.__stats = stats project = GlobalData().project if project.isLoaded(): self.__projectPrefix = os.path.dirname(project.fileName) else: self.__projectPrefix = os.path.dirname(scriptName) if not self.__projectPrefix.endswith(os.path.sep): self.__projectPrefix += os.path.sep self.__createLayout() self.__getDiagramLayout() self.__viewer.setScene(self.__scene) return def setFocus(self): " Sets the focus properly " self.__viewer.setFocus() return def __isOutsideItem(self, fileName): " Detects if the record should be shown as an outside one " return not fileName.startswith(self.__projectPrefix) def __createLayout(self): " Creates the widget layout " totalCalls = self.__stats.total_calls totalPrimitiveCalls = self.__stats.prim_calls # The calls were not induced via recursion totalTime = self.__stats.total_tt txt = "<b>Script:</b> " + self.__script + " " + self.__params.arguments + "<br>" \ "<b>Run at:</b> " + self.__reportTime + "<br>" + \ str( totalCalls ) + " function calls (" + \ str( totalPrimitiveCalls ) + " primitive calls) in " + \ FLOAT_FORMAT % totalTime + " CPU seconds" summary = QLabel(txt) summary.setToolTip(txt) summary.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) summary.setFrameStyle(QFrame.StyledPanel) summary.setAutoFillBackground(True) summaryPalette = summary.palette() summaryBackground = summaryPalette.color(QPalette.Background) summaryBackground.setRgb(min(summaryBackground.red() + 30, 255), min(summaryBackground.green() + 30, 255), min(summaryBackground.blue() + 30, 255)) summaryPalette.setColor(QPalette.Background, summaryBackground) summary.setPalette(summaryPalette) self.__scene = QGraphicsScene() self.__viewer = DiagramWidget() self.__viewer.escapePressed.connect(self.__onESC) vLayout = QVBoxLayout() vLayout.setContentsMargins(0, 0, 0, 0) vLayout.setSpacing(0) vLayout.addWidget(summary) vLayout.addWidget(self.__viewer) self.setLayout(vLayout) return def __getDiagramLayout(self): " Runs external tools to get the diagram layout " # Preparation: build a map of func ID -> fileName + line funcMap = {} index = 0 for func, props in self.__stats.stats.items(): funcMap[index] = (func[0], func[1]) index += 1 # First step is to run grpof2dot gprof2dot = thirdpartyDir + "gprof2dot" + os.path.sep + "gprof2dot.py" outputFile = self.__dataFile + ".dot" nodeLimit = Settings().profileNodeLimit edgeLimit = Settings().profileEdgeLimit dotSpec = safeRun([ gprof2dot, '-n', str(nodeLimit), '-e', str(edgeLimit), '-f', 'pstats', '-o', outputFile, self.__dataFile ]) graphDescr = safeRun(["dot", "-Tplain", outputFile]) graph = getGraphFromPlainDotData(graphDescr) graph.normalize(self.physicalDpiX(), self.physicalDpiY()) self.__scene.clear() self.__scene.setSceneRect(0, 0, graph.width, graph.height) for edge in graph.edges: self.__scene.addItem(FuncConnection(edge)) if edge.label != "": self.__scene.addItem(FuncConnectionLabel(edge)) for node in graph.nodes: fileName = "" lineNumber = 0 isOutside = True nodeID, newLabel = extractNodeID(node.label) if nodeID != -1: node.label = newLabel # Now, detect the file name/line number and # if it belongs to the project (fileName, lineNumber) = funcMap[nodeID] self.__scene.addItem( Function(node, fileName, lineNumber, self.__isOutsideItem(fileName))) return def __onESC(self): " Triggered when ESC is clicked " self.escapePressed.emit() return def onCopy(self): " Copies the diagram to the exchange buffer " self.__viewer.onCopy() return def onSaveAs(self, fileName): " Saves the diagram to a file " self.__viewer.onSaveAs(fileName) return def zoomIn(self): " Triggered on the 'zoom in' button " self.__viewer.zoomIn() return def zoomOut(self): " Triggered on the 'zoom out' button " self.__viewer.zoomOut() return def resetZoom(self): " Triggered on the 'zoom reset' button " self.__viewer.resetZoom() return
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 Printer(object): """For printing in diferent card formats and sizes the associated deck, be it to the screen or pdfs or image files""" card_sizes = {"Jumbo":(3.5,5.5), "Tarot":(2.75,4.75), "Square":(3.5,3.5), "Poker":(2.5,3.5), "Bridge":(2.25,3.5), "Biz":(2,3.5), "Mini":(1.75,2.5), "Micro":(1.25,1.75)} paper_sizes = {"A0":(33.1,46.8), "A1":(23.4,33.1), "A2":(16.5,23.4), "A3":(11.7,16.5), "A4":(8.3,11.7), "A5":(5.8,8.3), "A6":(4.1,5.8)} #TODO paper margins when printing and centering the images def __init__(self, deck=None): self.deck = deck self.scene = QGraphicsScene() self.orientation = getattr(QPrinter, "Portrait") self.path = "output.pdf" self.paper = getattr(QPrinter, "A4") self.card_size = Printer.card_sizes["Poker"] def config(self, *args, **kwargs): """kwargs: deck, card_size, paper_size, orientation, print_path if card_size is present I have to join the elements of the deck following the premises""" if "orientation" in kwargs: self.orientation = kwargs["orientation"] if "card_size" in kwargs: self.card_size = Printer.card_sizes[kwargs["card_size"][:kwargs["card_size"].find(" ")]] if "print_path" in kwargs: self.path = kwargs["print_path"] if "paper_size" in kwargs: self.paper = kwargs["paper_size"] if "deck" in kwargs: self.deck = kwargs["deck"] def print_grid(self): if self.deck is not None: #Setting the printer printer = QPrinter(QPrinter.HighResolution) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOrientation(getattr(QPrinter, self.orientation)) printer.setOutputFileName(self.path) printer.setPaperSize(getattr(QPrinter, self.paper)) #Start printing with QPainter(printer) as paint: first = True for c in self.deck: if not first: printer.newPage() first = False self.preview_card(c) self.scene.render(paint) def max_cards(self): """Taking in count the card_size, paper_size returns the max number of cards per page, horientation and margins""" port = {} port["orientation"] = "Portrait" pw = self.paper_sizes[self.paper][0] ph = self.paper_sizes[self.paper][1] port["horizontal"] = int(pw//self.card_size[0]) port["vertical"] = int(ph//self.card_size[1]) port["max"] = port["horizontal"] * port["vertical"] port["margin_horizontal"] = (pw % self.card_size[0]) / 2.0 port["margin_vertical"] = (ph % self.card_size[1]) / 2.0 land = {} land["orientation"] = "Landscape" pw = self.paper_sizes[self.paper][1] ph = self.paper_sizes[self.paper][0] land["horizontal"] = int(pw//self.card_size[0]) land["vertical"] = int(ph//self.card_size[1]) land["max"] = land["horizontal"] * land["vertical"] land["margin_horizontal"] = (pw % self.card_size[0]) / 2.0 land["margin_vertical"] = (ph % self.card_size[1]) / 2.0 if land["max"] > port["max"]: return land else: return port def print_pdf(self): if self.deck is not None: #Setting the printer printer = QPrinter(QPrinter.HighResolution) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOrientation(getattr(QPrinter, "Portrait")) printer.setOutputFileName(self.path) printer.setPaperSize(getattr(QPrinter, self.paper)) printer.setFullPage(True) guide = self.max_cards() printer.setOrientation(getattr(QPrinter, guide["orientation"])) print guide, self.card_size #Start printing with QPainter(printer) as paint: ind = 0 resol = printer.resolution() for c in self.deck: c.resize(self.card_size[0], self.card_size[1]) if ind == guide["max"]: printer.newPage() ind = 0 col = ind % guide["horizontal"] fil = ind // guide["horizontal"] print ind, fil, col target = QRectF((col)*self.card_size[0]*resol, (fil)*self.card_size[1]*resol, self.card_size[0]*resol, self.card_size[1]*resol) self.preview_card(c) self.scene.render(paint, target=target, source=QRectF(0,0,c.width(),c.height())) ind += 1 def save_images(self): if self.deck is not None: num = 1 for c in self.deck: c.save_as("".join([str(self.path),str(num),".",c.format()])) num += 1 def preview_card(self, card): try: self.scene.clear() ret = self.scene.addPixmap(card.pixmap()) except: self.scene.clear() ret = self.scene.addText("Image not available") return ret
class OWMosaicDisplay(OWWidget): name = "Mosaic Display" description = "Display data in a mosaic plot." icon = "icons/MosaicDisplay.svg" priority = 220 inputs = [("Data", Table, "set_data", Default), ("Data Subset", Table, "set_subset_data")] outputs = [("Selected Data", Table)] settingsHandler = DomainContextHandler() use_boxes = Setting(True) variable1 = ContextSetting("", exclude_metas=False) variable2 = ContextSetting("", exclude_metas=False) variable3 = ContextSetting("", exclude_metas=False) variable4 = ContextSetting("", exclude_metas=False) selection = ContextSetting(set()) # 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" class Warning(OWWidget.Warning): incompatible_subset = Msg("Data subset is incompatible with Data") no_valid_data = Msg("No valid data") no_cont_selection_sql = \ Msg("Selection of continuous variables on SQL is not supported") 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) if not self.data: self.discrete_data = None return 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): self.Warning.incompatible_subset.clear() if self.data is None: self.unprocessed_subset_data = data return try: self.subset_data = data.from_table(self.data.domain, data) except: self.subset_data = None self.Warning.incompatible_subset(shown=data is not None) # 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 = set() 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.no_cont_selection_sql.clear() if self.discrete_data is not self.data: if isinstance(self.data, SqlTable): self.Warning.no_cont_selection_sql() 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.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 = to_html(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.no_valid_data() return else: self.Warning.no_valid_data.clear() 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 ImageGrabber(object): ''' classdocs ''' _config = mrConfigParser() _gui = GuiLoader() _img = None __sources = [] __grabTimer = QTimer() __scene = None __gview = None def __init__(self, gui=None, config=None): ''' Constructor ''' self._gui = GuiLoader() self._config = config if gui != None: self._gui = gui self.__initGui() def __initGui(self): ''' Initiates gui listeners ''' # initiate scene self.__gview = self._gui.getObj("imgVideo") self.__scene = QGraphicsScene() self.__gview.setScene(self.__scene) # add image size combobox items cmb = self._gui.getObj("cmbImgSize") cmb.addItem("320x240") cmb.addItem("640x480") cmb.addItem("800x600") cmb.addItem("1024x768") #cmb.addItem("1280x960") # not working with libdc1394 and avt stringray 125c # add conversion combobox items cmb = self._gui.getObj("cmbConversion") cmb.addItem("None") cmb.addItem("COLOR_BGR2RGB") cmb.addItem("COLOR_GRAY2RGB") cmb.addItem("COLOR_YUV2RGB") cmb.addItem("COLOR_HLS2RGB") # add listeners self._gui.connect("cmdStartVideo", "clicked()", self.startVideo) self._gui.connect("cmdStopVideo", "clicked()", self.stopVideo) self._gui.connect("cmdAddSource", "clicked()", self.__addCamSource) self._gui.connect("cmdAddFile", "clicked()", self.__addFileSource) self._gui.connect("cmdDelSource", "clicked()", self.__removeSourceFromList) self._gui.connect("cmbImgSize", "currentIndexChanged(QString)", self.__imageSizeChanged) self._gui.connect("cmdSaveImg", "clicked()", self.saveImg) def isActive(self): ''' @return: True if image grabbing is active ''' return self.__grabTimer.isActive() def startVideo(self): ''' Starts grabbing images ''' if self.__grabTimer.isActive(): self.__grabTimer.stop() self.__grabTimer = QTimer() self.__grabTimer.timeout.connect(self.__grabImage) self.__grabTimer.start(0) self._gui.status("Video started") def stopVideo(self): ''' Stops grabbing video ''' if self.__grabTimer.isActive(): self.__grabTimer.stop() self.__scene.clear() self.__gview.show() self._gui.status("Video stopped") sleep(1) def getImage(self): ''' Returns the last grabbed image @return: Image ''' return self._img def saveImg(self): ''' Saves image ''' if self._img != None: img = self._img # stop video active = self.isActive() self.stopVideo() # open file dialog options = copy(self._gui.dialogOptionsDef) options['type'] = self._gui.dialogTypes['FileSave'] options['filetypes'] = "JPG (*.jpg)" options['title'] = "Save current frame as" src = str(self._gui.dialog(options)) # check filepath and save if len(src) > 0: if not src.endswith(".jpg"): src = src + ".jpg" self._gui.status("write to " + src) cvtColor(img, COLOR_BGR2RGB) imwrite(src, img) # reset video streaming if active: self.startVideo() def __showImage(self): ''' Shows image on graphics view ''' if self._img != None: self.__scene.clear() self.__scene.addPixmap(imageToPixmap(self._img)) self.__gview.fitInView(self.__scene.sceneRect(), Qt.KeepAspectRatio) self.__gview.show() def __grabImage(self): ''' Graps image from sources ''' images = [] # grab all images for src in self.__sources: assert isinstance(src, AbstractSourceGrabber) images.append(src.getImg()) # join and convert images img = self.__joinImages(images) # convert image convert = eval(str(self._gui.getObj("cmbConversion").currentText())) if convert != None: try: img = cvtColor(img, convert) except: img = None # show results if type(img) == ndarray: # add image as new image self._img = img self.__showImage() else: # show message self.__scene.clear() self.__scene.addText("NO VIDEO") def __joinImages(self, images=[]): ''' Joins images ''' # TO-DO: Joining images if len(images) > 0: return images[0] return False def __imageSizeChanged(self, size="640x480"): ''' Changes image size ''' size = str(size).split("x") w = int(size[0]) h = int(size[1]) # set size for cam in self.__sources: if type(cam) == CamGrabber: assert isinstance(cam, CamGrabber) cam.setImgSize(w, h) def __addSourceToList(self, grabber=None): ''' Adds source to source list ''' assert isinstance(grabber, AbstractSourceGrabber) if grabber != None: # add grabber to list self.__sources.append(grabber) txt = None # get type of grabber if type(grabber) == CamGrabber: txt = "cam [" + str(grabber.getSource()) + "]" elif type(grabber) == FileGrabber: txt = "file [" + str(grabber.getSource()) + "]" # add text string to gui list if txt != None: self._gui.getObj("lstSources").addItem(txt) def __removeSourceFromList(self): ''' Removes selected source from list ''' for item in self._gui.getObj("lstSources").selectedItems(): # get item informationen txt = str(item.text()) if "[" in txt and "]" in txt: data = txt.split("[") iType = data[0].strip() iSource = data[1].replace(']', '') # search for grabber for grabber in self.__sources: assert isinstance(grabber, AbstractSourceGrabber) if str(grabber.getSource()) == iSource: if type(grabber) == CamGrabber and iType == "cam": self.__sources.remove(grabber) break elif type(grabber) == FileGrabber and iType == "file": self.__sources.remove(grabber) break # remove source from gui list item = self._gui.getObj("lstSources").takeItem( self._gui.getObj("lstSources").currentRow()) item = None def __addCamSource(self): ''' Adds camera as source ''' obj = self._gui.getObj("txtSource") source = int(obj.text()) grabber = CamGrabber(source) if grabber.isOpened(): self.__addSourceToList(grabber) self._gui.status("Added camera source [" + str(source) + "]") else: self._gui.status( "Could not add camera source [" + str(source) + "]", self._gui.msgTypes['ERROR']) def __addFileSource(self): ''' Adds file as source ''' self.stopVideo() options = copy(self._gui.dialogOptionsDef) options['filetypes'] = "Images (*.jpg *jpeg *gif *png *bmp *tif)" source = str(self._gui.dialog(options)) if len(source) > 0: grabber = FileGrabber(source) self.__addSourceToList(grabber) self._gui.status("Added file source [" + str(source) + "]")
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): QObject.__init__(self) 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.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): print "Setting Drawnnumer", 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): self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001) line = self.moveTo(pos) return line def endDrawing(self, pos): self.moveTo(pos) 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() 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): oldX, oldY = self.pos.x(), self.pos.y() x,y = pos.x(), pos.y() #print "BrushingModel.moveTo(pos=%r)" % (pos) line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(x,y), 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
def clear(self): QGraphicsScene.clear(self) self.G.clear() del self.nodes[:] del self.edges[:]
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 CVViewModel(object): """docstring for View""" def __init__(self, ): super(CVViewModel, self).__init__() self.scence = QGraphicsScene() self.graphicsView.setScene(self.scence) self.beginTestCV.clicked.connect( partial(self.beginTestCV.setEnabled, False)) self.reporterCV.clicked.connect(self.writeReporterCV) self.updateCVData.clicked.connect(self.write_cv_result_to_db) # if hasattr(self,"updateOPData"): # self.updateOPData.clicked.connect(self.write_cv_result_to_db) self.updata_CV_method = update_cv_data self.db_parameters,self.pdf_parameters = config.DB_PARAMETER,config.PDF_PARAMETER self.insert_widgets() self.emit_fibertype_in_items = PyTypeSignal() self.last_save = {} self._last_data_init() self.emit_close_event = PyTypeSignal() self.to_report = ReporterPdfs def insert_widgets(self): self.relative_index_canvas = RefractCanvas(QWidget(self.extendwidget), width=5, height=2, dpi=100) self.cvOperatorLayout.insertWidget(2, self.relative_index_canvas) def _last_data_init(self): load = load_pickle_nor_json("setting\\userdata") types = load.get("fiberTypes") self.fiberTypeBox.addItems(types) # now = self.fiberTypeBox.currentText() self.emit_fibertype_in_items.emit() try: self.olddata = WriteReadJson('setting\\old.json') self.last_save = self.olddata.load() except ValueError: return if self.last_save: self.fiberLength.setText(self.last_save['fiberLength']) self.Worker.setText(self.last_save['worker']) self.factory.setText(self.last_save['producer']) self.fiberNumber.setText(self.last_save['fiberNo']) def updatePixmap(self, arr, sharp, light): height, width, bytesPerComponent = arr.shape bytesPerLine = bytesPerComponent * width img = QImage(arr.data, width, height, bytesPerLine, QImage.Format_RGB888) pximapimg = QPixmap.fromImage(img) self.scence.clear() self.scence.addPixmap(pximapimg) self.dynamicSharp.setText(sharp) self.light.setText(light) def enable_move_button(self, is_move=True): collections = ("move_down", "move_up", "next_state", "move_right", "move_left", "reset") moves = {getattr(self, c) for c in collections} for move in moves: move.setEnabled(is_move) def closeEvent(self, event, *args, **kwargs): # if 'olddata' in SETTING().keys(): # self.olddata.save(SETTING()['olddata']) logger.info('get last save\n' + str(self.last_save)) # print(self.last_save) self.olddata.save(self.last_save) self.emit_close_event.emit() super(CVViewModel, self).closeEvent(event) def updateCVShow(self, str_, ): if str_: self.resultShowCV.setText(str_) # self.resultShowCV.setStyleSheet("QTextBrowser{font-family: \"Microsoft YaHei\";}") self.beginTestCV.setEnabled(True) def writeReporterCV(self): para = {} para['fiberLength'] = str(self.fiberLength.text()) para['worker'] = str(self.Worker.text()) para['producer'] = str(self.factory.text()) para['fiberNo'] = str(self.fiberNumber.text()) para['fibertype'] = str(self.fiberTypeBox.currentText()) para['fibertypeindex'] = str(self.fiberTypeBox.currentIndex()) para['date'] = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') para['title'] = para['fibertype'] + '光纤端面几何测试报告' self.pdf_parameters.update(para) # PDF_PARAMETER.update(para) self.last_save.update(para) self.to_report(self) # print 'get in session' self.db_parameters.update(para) # dbpara = SETTING()['dbpara'] def write_cv_result_to_db(self): para = {} para['fiberLength'] = str(self.fiberLength.text()) para['worker'] = str(self.Worker.text()) para['producer'] = str(self.factory.text()) para['fiberNo'] = str(self.fiberNumber.text()) para['fibertype'] = str(self.fiberTypeBox.currentText()) para['fibertypeindex'] = str(self.fiberTypeBox.currentIndex()) para['date'] = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') para['sharpindex'] = float(self.dynamicSharp.text()) self.db_parameters.update(para) # session_add_by_account(DB_PARAMETER) self.updata_CV_method(self.db_parameters) # def getCoreLight(self, coreLight, cladLight): # if hasattr(self, "coreLight"): # self.coreLight.setText(coreLight) # if hasattr(self, "cladLight"): # self.cladLight.setText(cladLight) def relative_index_show(self, plots): self.relative_index_canvas.update_figure(*plots)
class DrawManager(QObject): """ DEPRECATED. Will be replaced with BrushingModel, BrushingControler, BrushStroke. """ brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black def __init__(self): QObject.__init__(self) self.shape = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self.drawnNumber = self.defaultDrawnNumber self.penVis = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.penDraw = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.pos = None self.erasing = False #on which layer do we want to draw when self.drawingEnabled? 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 growBoundingBox(self): self.bb.setLeft( max(0, self.bb.left()-self.brushSize-1)) self.bb.setTop( max(0, self.bb.top()-self.brushSize-1 )) self.bb.setRight( min(self.shape[0], self.bb.right()+self.brushSize+1)) self.bb.setBottom(min(self.shape[1], self.bb.bottom()+self.brushSize+1)) def toggleErase(self): self.erasing = not(self.erasing) def setErasing(self): self.erasing = True self.brushColorChanged.emit(self.erasingColor) def disableErasing(self): self.erasing = False self.brushColorChanged.emit(self.drawColor) def setBrushSize(self, size): self.brushSize = size self.penVis.setWidth(size) self.penDraw.setWidth(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.penVis.setColor(color) self.emit.brushColorChanged(self.drawColor) def beginDrawing(self, pos, shape): self.shape = shape self.bb = QRectF(0, 0, self.shape[0], self.shape[1]) self.scene.clear() if self.erasing: self.penVis.setColor(self.erasingColor) else: self.penVis.setColor(self.drawColor) self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001) line = self.moveTo(pos) return line def endDrawing(self, pos): self.moveTo(pos) self.growBoundingBox() 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, QRectF(QPointF(0,0), self.bb.size()), self.bb) return (self.bb.left(), self.bb.top(), tempi) #TODO: hackish, probably return a class ?? def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.shape) return res def moveTo(self, pos): lineVis = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y()) lineVis.setPen(self.penVis) line = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y()) line.setPen(self.penDraw) self.scene.addItem(line) self.pos = pos x = pos.x() y = pos.y() #update bounding Box : if x > self.bb.right(): self.bb.setRight(x) if x < self.bb.left(): self.bb.setLeft(x) if y > self.bb.bottom(): self.bb.setBottom(y) if y < self.bb.top(): self.bb.setTop(y) return lineVis
class CBIR(QMainWindow, Ui_MainWindow): #class variables flag = True categories = {} classes = [ "Aeroplane", "Bicycle", "Bird", "Boat", "Bottle", "Bus", "Car", "Cat", "Chair", "Cow", "Dining Table", "Dog", "Horse", "Motorbike", "Person", "Potted plant", "Sheep", "Sofa", "Train", "Tv" ] mask = np.zeros(len(classes)) class2idx = {item: i for i, item in enumerate(classes)} valid_images = ["jpg", "png", "tga", "pgm", "jpeg"] valid_videos = ["mp4", "avi"] edge_threshold = 100 topk = 10 to_disp = [] stop = False database_path = '' thumbnail_size = 256 spacing = 40 images_per_row = 2 cached_db = {} cached_db_path = '' alpha = 16 beta = 0.8 def __init__(self, ): super( CBIR, self).__init__() #initialise from the ui designed by Designer App self.setupUi(self) self.setupUi_custom() def setupUi_custom(self, ): self.setWindowTitle('CBIR') #setup space to display selected image and it's tagged version self.scene = QGraphicsScene() self.scene2 = QGraphicsScene() #connect the buttons to their respective functions self.pushButton.clicked.connect(self.select_image) self.pushButton_2.clicked.connect(self.find_similar) self.pushButton_3.clicked.connect(self.select_database) self.horizontalSlider.valueChanged.connect(self.update_LCD) #TODO [WEIRD PROBLEM] QPixmap needs to be called at least once with JPG image before tensorFlow, otherwise program crashes self.scene.addPixmap( QPixmap(os.getcwd() + "/images/demo.jpg").scaled( self.graphicsView.size(), QtCore.Qt.KeepAspectRatio)) self.graphicsView.setScene(self.scene) #set-up toolbar items and link them to respective functions Help = QtGui.QAction(QtGui.QIcon('images/info.png'), 'Help', self) Help.triggered.connect(self.show_help) Settings = QtGui.QAction(QtGui.QIcon('images/settings.png'), 'Settings', self) Settings.triggered.connect(self.show_settings) Export = QtGui.QAction(QtGui.QIcon('images/export.png'), 'Export', self) Export.triggered.connect(self.show_export) ##To set up the toolbar self.toolbar = self.addToolBar('Help') self.toolbar.addAction(Help) self.toolbar = self.addToolBar('Settings') self.toolbar.addAction(Settings) self.toolbar = self.addToolBar('Export') self.toolbar.addAction(Export) def show_help(self): msg = QMessageBox() #setup title, main heading, about us info msg.setIcon(QMessageBox.Information) msg.setWindowTitle("About Us") msg.setText("Semantic Graph based Image matching") msg.setInformativeText( "Developed by Yash Chandak, under supervision of Prof. Babiga Birregah, University of Technology, Troyes" ) #Section for further details on how to use the software f = open('How-To/how-to-SGBIR.txt', 'r') msg.setDetailedText(f.read()) #setup return buttons msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def show_settings(self): topk, ok = QtGui.QInputDialog.getInt(self, 'Settings', 'Number of results to display') self.topk = topk def show_export(self): #TODO gephi export name, ok = QtGui.QInputDialog.getText(self, 'Export to Gephi format', 'Enter file name :') self.exportname = name def select_database(self): #Read all the images in the folder path = QFileDialog.getExistingDirectory( None, 'Select a folder:', '/home/yash/Project/dataset/Pascal VOC 2012/', QtGui.QFileDialog.ShowDirsOnly) self.lineEdit_2.setText(path) self.database_path = path def update_categories(self): #update selected categories self.mask.fill(0) for radiobox in self.findChildren(QtGui.QRadioButton): self.categories[radiobox.text()] = radiobox.isChecked() if not radiobox.text() == 'All': self.mask[self.class2idx[ radiobox.text()]] = radiobox.isChecked() if self.categories.get('All', 0) == 1: self.mask.fill(1) def update_LCD(self): #update edge_threshold variable based on slider self.edge_threshold = self.horizontalSlider.value() self.lcdNumber.display(self.edge_threshold) def show_similar(self, pictures, base_dir=''): #set the table layout spacing self.tableWidget.setMinimumWidth((self.thumbnail_size + self.spacing) * self.images_per_row + (self.spacing * 2)) #set table row and column count based on similar images received rowCount = len(pictures) // self.images_per_row if len(pictures) % self.images_per_row: rowCount += 1 self.tableWidget.setRowCount(rowCount) row = -1 #set the pictures in the table cells for i, picture in enumerate(pictures): col = i % self.images_per_row if not col: row += 1 #self.tableWidget.setCellWidget(row, col, ImgWidget(imagePath = self.cached_db[picture][0], size=self.thumbnail_size)) self.tableWidget.setCellWidget( row, col, ImgWidget(imagePath=base_dir + '/' + picture, size=self.thumbnail_size)) def read_database(self): #Option to select database if self.database_path == '': print("Database file not selected") self.select_database() found = False if self.cached_db_path == self.database_path: #No need to re-read from cPickle if it's re-run on the same db found = True #Search for any pre-existing db file else: self.cached_db_path = self.database_path for file in os.listdir( self.database_path): #list all the files in the folder extension = file.split('.')[1] #get the file extension if extension.lower( ) == 'db': #check for pickled cached_db file self.cached_db = pickle.load( open(self.database_path + '/' + file, 'rb')) print("Cached database found!") found = True break #Create a new db if no exiting db is found if not found: self.cached_db = self.make_db(self.database_path) def count_diff(self, v1, v2): #alpha acts as a hyper-parameter that penalizes count differneces of #classes present only in one as compared to count differneces for classes #present in both. w = [self.alpha if i == 0 else 1 for i in v1] return np.sum(self.mask * w * np.power( (v1 - v2), 2)) #sum of weighted Squared error, masked by selected classes def loc_diff(self, query_edges, db_edges): total = 0 for e1 in query_edges: best = 99999 for e2 in db_edges: if e1[0] == e2[0]: diff = abs(e1[1] - e2[1]) best = diff if diff < best else best total += best #TODO: add the details return np.log(total) def score(self, edges, vec, db_img): #weighted score of location deifference and count difference #higher the score, higher is the difference, lesser the similarity return self.beta*self.count_diff(vec, self.cached_db['vec'][db_img]) \ + (1-self.beta)*self.loc_diff(edges, self.cached_db['edges'][db_img]) def get_vec_and_classes(self, results): #returns vector and all unique classes for the given image result. vec = np.zeros(len(self.classifier.classes)) classes_present = [] for result in results: vec[self.class2idx[result[0]]] += 1 classes_present.append(result[0]) return vec, set(classes_present) def order(self, c1, c2): #edge nodes concatenated in alphabetical order to create edge name if self.class2idx[c1] < self.class2idx[c2]: return c1 + c2 else: return c2 + c1 def get_edges_with_weights(self, results): #returns a list of (edge, weight) return [(self.order(results[i][0], results[j][0]), apx_distance(results[i], results[j])) \ for i in range(len(results)) for j in range(i, len(results))] def make_db(self, path): print("caching database..") inv_map = {c: [] for c in self.classes} edges = {} vec = {} for file in os.listdir(path): #list all the fileiles in the folder ext = file.split('.')[1] #get the file extension if ext.lower() in self.valid_images: print(file) full_path = path + '/' + file self.tag_image(filename=full_path) #store the all the edges and weights for the image edges[file] = self.get_edges_with_weights( self.classifier.result) #create the inverse map( class -> images ) v, classes_present = self.get_vec_and_classes( self.classifier.result) vec[file] = v for c in classes_present: inv_map[c].append(file) #Storage format = {dir, inv_map[class]->images, vectors[image]->vec, edges[image]->edges} cached_db = { 'dir': path, 'inv_map': inv_map, 'vec': vec, 'edges': edges } pickle.dump(cached_db, open(path + '/cache.db', 'wb')) return cached_db def find_similar(self, results): #do pattern matching on the images in retrieved cached_db #keep top 10 and display on right self.read_database() #get the edges, vector, classes_present in the query image edges = self.get_edges_with_weights(results) vec, classes_present = self.get_vec_and_classes(results) #get all the images having at least one occurence of the class present in query image imgs = set([ img for c in classes_present for img in self.cached_db['inv_map'][c] ]) #choose the topK similar images from the images retrieved from database best_matches = nsmallest(self.topk, imgs, key=lambda e: self.score(edges, vec, e)) self.show_similar(best_matches, self.cached_db['dir']) return best_matches[:5] def tag_image(self, filename=None, batch=False, image=None): #importing TensorFlow on top causes segmentation fault (official bug #2034) #importing here helps in working around the problem #Python modules could be con)sidered as singletons... so no matter how many times they are imported, they get initialized only once import Yolo_module as yolo if (self.flag): #initialise the model, only once self.classifier = yolo.YOLO_TF() self.flag = False self.classifier.batch = batch if not image == None: self.classifier.detect_from_cvmat(image) else: self.classifier.detect_from_file( filename) #execute Yolo on the image return self.classifier.tagged_image def disp_img(self, filename=None, img=None): if not img == None: img_rgb = img.copy() #convert image to PyQt display format cv2.cvtColor(img, cv2.COLOR_BGR2RGB, img_rgb) img_rgb = QtGui.QImage(img_rgb, img_rgb.shape[1], img_rgb.shape[0], img_rgb.shape[1] * 3, QtGui.QImage.Format_RGB888) self.scene.addPixmap( QPixmap(img_rgb).scaled(self.graphicsView.size(), QtCore.Qt.KeepAspectRatio)) image = self.tag_image(image=img) else: #DO this step before calling tensorflow self.scene.addPixmap( QPixmap(filename).scaled(self.graphicsView.size(), QtCore.Qt.KeepAspectRatio)) #Dislplay tagged image image = self.tag_image(filename=filename) image = QtGui.QImage( image, image.shape[1], image.shape[0], image.shape[1] * 3, QtGui.QImage.Format_RGB888) #convert to Qt image format self.scene2.addPixmap( QPixmap(image).scaled(self.graphicsView_3.size(), QtCore.Qt.KeepAspectRatio)) self.graphicsView.setScene(self.scene) self.graphicsView_3.setScene(self.scene2) def select_image(self): #Clear previous image displays self.scene.clear() self.scene2.clear() self.tableWidget.clearContents() self.update_categories( ) #update categories to incorporate any changes made #Change the file path to any default directory, as per need. filename = QFileDialog.getOpenFileName( directory='/home/yash/Project/dataset/Pascal VOC 2012/') self.lineEdit.setText(filename) if filename.split('.')[1] in self.valid_images: self.disp_img(filename=filename) self.file_tag = '/home/yash/Project/dataset/Pascal VOC 2012/report/' + ( filename.split('/')[-1]).split('.')[0] + "_" best_matches = self.find_similar(self.classifier.result) cv2.imwrite(self.file_tag + '.jpg', cv2.imread(filename, 1)) cv2.imwrite(self.file_tag + 'tagged.jpg', self.classifier.tagged_image_original) for idx, im in enumerate(best_matches): cv2.imwrite(self.file_tag + str(idx) + '.jpg', cv2.imread(self.cached_db['dir'] + '/' + im, 1)) #self.find_similar_using_vector(self.classifier.result) else: print("Invalid file format")
class ToastWidget(QGraphicsView): """ A widget to create toast messages to the user A friendly interface messages. (include image, and visual effects as blinking, fade etc) """ def __init__(self, parent=None, back_image=None, width=100, heigth=100): super(ToastWidget, self).__init__(parent) self.setWindowFlags(Qt.SplashScreen) self.scene = QGraphicsScene(self) self.timer = QTimer(self) self.setScene(self.scene) self.set_image(back_image) self.setGeometry(QRect(self.x(), self.y(), width, heigth)) self.show() def set_image(self, image): if image is None: return if not isinstance(image, QPixmap): raise Exception("Image must be of type QPixmap") self.scene.clear() self.scene.addPixmap(image.scaled(95, 95)) def move_random(self, x1=0, x2=1300, y1=0, y2=768): x, y = random.randrange(x1, x2), random.randrange(y1, y2) self.setGeometry(QRect(x, y, 100, 100)) return self def blink(self, time_limit=1000, time_interval=500): def _blink(): self.setWindowOpacity(1 - self.windowOpacity()) # self.timer.stop() # self.timer.setInterval(time_interval) # self.timer.timeout.connect(_blink) # self.timer.start_limited(time_interval, time_limit / time_interval) return self def fade(self, time=1500): """ :param time: the time to completely execute the fade in ms :param out: fade out or in. out by default """ steps = 100 self.timer.stop() self.setWindowOpacity(1) self.timer.timeout.connect( lambda: self.setWindowOpacity(self.windowOpacity() - 1.0 / steps)) self.timer.start(time * 1.0 / steps) # QTimer.singleShot(time, lambda: self.timer.stop()) return self def disappear(self, time=1000): """ """ self.timer.stop() self.setWindowOpacity(1) self.timer.singleShot(time, lambda: self.setWindowOpacity(0)) return self def vibrate(self, time_limit=1000): geometry = self.geometry() x, y = geometry.x(), geometry.y() def _move(): self.setGeometry( QRect(x + random.randrange(-3, 3), y + random.randrange(-3, 3), geometry.width(), geometry.height())) return self
class AnalogClock(QGraphicsView): """ Analog Clock Widget. It shows a analog svg clock """ AUTO = 0 QUARTZ = 1 ECO = 2 def __init__(self, parent=None, path=None, static = False): """ Constructor """ QGraphicsView.__init__(self, parent) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) #self.setAutoFillBackground(True) #pal = self.palette(); #br = QBrush(Qt.NoBrush) #pal.setBrush(QPalette.Background, br); #self.setPalette(pal); #self.setBackgroundBrush(br) # is the only thing seems to work to get the background transparent self.setStyleSheet("background-color: rgba(0, 0, 0, 0%);") self.setFrameShape(QFrame.NoFrame) # self.setBackgroundOrigin( BackgroundOrigin background ) self._static = static self.setDefaults() self.loadTheme(path) self.startTimers() self.resetEcoTimer() #self.setClockType() def setDefaults(self): self.sysThemeDir=os.path.join(os.path.dirname(__file__), os.path.pardir, "theme") self.themeDir="" self.themeName="" self.ecoTimeout = 0 self.clockMode = self.AUTO self.drop="clock-drop-shadow.svg" self.face="clock-face.svg" self.shadow="clock-face-shadow.svg" self.marks= "clock-marks.svg" self.frame="clock-frame.svg" self.hourHand="clock-hour-hand.svg" self.minuteHand="clock-minute-hand.svg" self.secondsHand="clock-second-hand.svg" self.glass="clock-glass.svg" #Variables that keep track of the angle of the hands, and Time self.secTimer = QBasicTimer() self.minTimer=QTimer() self.calibrateTimer=QTimer() self.ecoTimer=QTimer() self.syncTimer=QTimer() self.secs=0 #The second hand counter 166=6 beats per second, 1000 =1 beat per sec self.secTimerType=166.9 self.secTimerBeat=1 #The Minute update counter every 10secs for Quartz, once per minute for Eco self.minTimerType=1000 #Variables that keep track of scene self.scene = QGraphicsScene() self.sceneWidth=0 self.sceneHeight=0 self.centerx=0 self.centery=0 self.xoffset=-15 self.yoffset=-5 self.ixoffset=self.xoffset*-1 self.iyoffset=self.yoffset*-1 self.svgRect=QRect() self.svgRect.setX(self.xoffset) self.svgRect.setY(self.yoffset) def loadTheme(self, path): self.secTimer.stop() self.minTimer.stop() self.calibrateTimer.stop() self.syncTimer.stop() self.scene.clear() #Check to see if files in directory stored in QConfig exists self.themeDir=path or self.sysThemeDir try: f=open(os.path.join(self.themeDir, unicode(self.face))) except (OSError, IOError), e: print "can't load theme, loading default" #Initialize the Graphics Scene, Graphicsview is setup in QtDesigner UI,do not convert to a loop def path(suffix): return os.path.join(self.themeDir, self.themeName ,suffix) self.svgDrop=QGraphicsSvgItem(path(self.drop)) renderer=self.svgDrop.renderer() self.svgDrop.setZValue(1) self.scene.addItem(self.svgDrop) self.svgFace=QGraphicsSvgItem(path(self.face)) renderer=self.svgFace.renderer() self.svgFace.setZValue(2) self.scene.addItem(self.svgFace) self.svgShadow=QGraphicsSvgItem(path(self.shadow)) renderer=self.svgShadow.renderer() self.svgShadow.setZValue(4) self.scene.addItem(self.svgShadow) self.svgMarks=QGraphicsSvgItem(path(self.marks)) renderer=self.svgMarks.renderer() self.svgMarks.setZValue(5) self.scene.addItem(self.svgMarks) self.svgFrame=QGraphicsSvgItem(path(self.frame)) renderer=self.svgFrame.renderer() self.svgFrame.setZValue(6) self.scene.addItem(self.svgFrame) #get the bounding box for the scene now filled with the clock theme self.sceneWidth=self.scene.itemsBoundingRect().width() self.sceneHeight=self.scene.itemsBoundingRect().height() self.centerx=self.sceneWidth/2 self.centery=self.sceneHeight/2 self.centerOn(self.centerx, self.centery) self.scene.setSceneRect(0, 0,self.sceneWidth, self.sceneHeight) #===Load the Hour hand and scale the viewport to its size=========== self.svgHour=QGraphicsSvgItem(path(self.hourHand)) self.renderer=self.svgHour.renderer() self.rect=self.svgHour.boundingRect() self.svgRect.setWidth(self.rect.width()) self.svgRect.setHeight(self.rect.height()) #setup the Viewbox self.renderer.setViewBox(self.svgRect) self.svgHour.setPos(self.centerx+self.xoffset, self.centery+self.yoffset) self.svgHour.setZValue(7) self.scene.addItem(self.svgHour) #===Load the Minute hand and scale the viewport to its size=========== self.svgMinute=QGraphicsSvgItem(path(self.minuteHand)) self.renderer=self.svgMinute.renderer() self.rect=self.svgMinute.boundingRect() self.svgRect.setWidth(self.rect.width()) self.svgRect.setHeight(self.rect.height()) #setup the Viewbox self.renderer.setViewBox(self.svgRect) self.svgMinute.setPos(self.centerx+self.xoffset, self.centery+self.yoffset) self.svgMinute.setZValue(8) self.scene.addItem(self.svgMinute) #===Load the Seconds Hand and scale the viewport to its size=========== self.svgSecond=QGraphicsSvgItem(path(self.secondsHand)) self.renderer=self.svgSecond.renderer() self.rect=self.svgSecond.boundingRect() self.svgRect.setWidth(self.rect.width()) self.svgRect.setHeight(self.rect.height()) #setup the Viewbox self.renderer.setViewBox(self.svgRect) self.svgSecond.setPos(self.centerx+self.xoffset, self.centery+self.yoffset) self.svgSecond.setZValue(9) self.scene.addItem(self.svgSecond) #Add the Glass as the top layer self.fileExist=1 try: f=open (path("clock-glass.svg")) except : self.fileExist=0 if self.fileExist==1: self.svgItem=QGraphicsSvgItem(path(self.glass)) renderer=self.svgItem.renderer() self.svgItem.setZValue(10) self.scene.addItem(self.svgItem) #setup the hands against the current time self.showTime() self.calibrateTime() #Scale the Clock to full screen and show whole clock self.resetTransform() self.setZoom(None) self.setScene(self.scene)
class Distortion(visionModule): ''' classdocs ''' __imgScene = None __scene = None __gview = None __sceneImgTimer = None __camera_matrix = None __dist_coefs = None __corners = None __calibrated = False __calibrating = False def __init__(self, gui=None, imageGrabber=None, config=None): ''' Constructor ''' super(Distortion, self).__init__(gui=gui, imageGrabber=imageGrabber, config=config) self.__calibrated = False self.__calibrating = False if gui != None: self.__initGui() if self._config != None: cfgFile = self._config.getConfigValue("CONFIGURATION", "cfgCalibration") if cfgFile != None and self.__loadConfigData(cfgFile): self._gui.status( "Loaded distortion config." ) mrLogger.logInfo( "Loaded distortion config file " + str(cfgFile) ) def __initGui(self): ''' Initiates gui ''' # initiate scene self.__gview = self._gui.getObj("imgDistortion") self.__scene = QGraphicsScene() self.__gview.setScene(self.__scene) # create listeners self._gui.connect( "cmdFindPattern", "clicked()", self.findChessBoardPattern ) self._gui.connect( "cmdCalibrateDistortion", "clicked()", self.calibrateCamera ) self._gui.connect( "cmdSaveDistortion", "clicked()", self.__saveConfiguration ) self._gui.connect( "cmdLoadDistortion", "clicked()", self.__loadConfiguration ) self._gui.connect( "chkCropImg", "toggled(bool)", self.__borderSelectionChanged ) self._gui.connect( "chkCropImgManual", "toggled(bool)", self.__borderSelectionChanged ) self._gui.connect( "cmdSaveImgDistortion", "clicked()", self.__saveImg ) # start timer self.__sceneImgTimer = QTimer() self.__sceneImgTimer.timeout.connect( self._showImage ) self.__sceneImgTimer.start(200) def isCalibrated(self): ''' @return: True if image is calibrated ''' return self.__calibrated def isCalibrating(self): ''' @return: True if calibration is in progress ''' return self.__calibrating def setImg(self, img=None): ''' Sets current image ''' super(Distortion, self).setImg(img) if not self.isCalibrating() and self._imageGrabber != None: self.__imgScene = self.cropImage( self.undistortImage(self._img) ) def __borderSelectionChanged(self): ''' Checks selection of manual/auto border settings gui group ''' if self._gui.getObj("chkCropImgManual").isChecked(): self._gui.getObj("chkCropImg").setChecked(False) self._gui.getObj("chkCropImg").setEnabled(False) else: self._gui.getObj("chkCropImg").setEnabled(True) if self._gui.getObj("chkCropImg").isChecked(): self._gui.getObj("chkCropImgManual").setChecked(False) self._gui.getObj("chkCropImgManual").setEnabled(False) else: self._gui.getObj("chkCropImgManual").setEnabled(True) def findChessBoardPattern(self): ''' Finds maximum chessboard pattern ''' # show message self.__imgScene = None self.__scene.clear() self.__scene.addSimpleText("Searching pattern...\nThis will take a while") self.__gview.show() # start search start_new_thread( self.__searchChessBoardPattern, () ) def __searchChessBoardPattern(self): ''' Searches for chessboard pattern (start in background) ''' # get start and max values xStart = int( str( self._gui.getObj("txtPatternXMin").text() ) ) yStart = int( str( self._gui.getObj("txtPatternYMin").text() ) ) xMax = int( str( self._gui.getObj("txtPatternXMax").text() ) ) yMax = int( str( self._gui.getObj("txtPatternYMax").text() ) ) # find pattern if self._img != None: pattern = findChessBoardPatternSize(self._img, xMax, yMax, xStart, yStart) if pattern != None and len(pattern) > 0: # set pattern if len(pattern) == 2: self._gui.getObj("txtPatternX").setText( str(pattern[0]) ) self._gui.getObj("txtPatternY").setText( str(pattern[1]) ) def calibrateCamera(self): ''' Calibrates camera ''' start_new_thread(self.__calibrate, ()) def __calibrate(self): ''' Calibrates camera (run in background) ''' # check for correct image if self._img != None: self.__calibrating = True self._gui.status("Calibrating ...") # get values x = int(str( self._gui.getObj("txtPatternX").text() )) y = int(str( self._gui.getObj("txtPatternY").text() )) n = int(str( self._gui.getObj("txtCalibrationFrames").text() )) square_size = float(str( self._gui.getObj("txtCalibrationSquareSize").text() )) # calculate distortion pattern_size = (x, y) ret = self.__calibrateCorners(pattern_size, n, square_size) if ret != None: camera_matrix, dist_coefs = ret self.__camera_matrix, self.__dist_coefs = camera_matrix, dist_coefs # undistort image img = self.undistortImage(self._img) self.__imgScene = img self._gui.status("Searching for boders to crop image ...") # get corners if ret != None: found = False frames = 0; tries = 0; while not found and frames < n and tries < 10: img = self.undistortImage(self._img) found, corners = getChessBoardCorners( img, pattern_size ) if found: frames += 1 tries += 1 if found: self.__corners = getImageSizeFromCorners(corners) # crop image self.__imgScene = self.cropImage(img) self.__calibrated = True # set calibration flag self._gui.status("Calibration finished.") self.__calibrating = False def __calibrateCorners(self, pattern_size, n, square_size): ''' Calibrates corners of chessboard @return: camera_matrix, dist_coefs ''' pattern_points = zeros( (prod(pattern_size), 3), float32 ) pattern_points[:,:2] = indices(pattern_size).T.reshape(-1, 2) pattern_points *= square_size obj_points = [] img_points = [] frames = 0; tries = 0 lastCount = self._imgCounter; # detect pattern while frames < n and tries < 10: img = self._img img = cvtColor(img, COLOR_RGB2GRAY) img = threshold(img, 40, 255, THRESH_BINARY)[1] img = cvtColor(img, COLOR_GRAY2RGB) self.__imgScene = img from time import sleep sleep(1) if lastCount != self._imgCounter: # get corners print "getchessboardcorners" found, corners = getChessBoardCorners( img, pattern_size ) print "found", found # check if corners found if found: frames += 1 # get more detailed points and add them to list img_points.append( corners.reshape(-1, 2) ) obj_points.append( pattern_points ) # draw corners drawChessboardCorners( img, pattern_size, corners, found ) self.__imgScene = img tries = 0 tries += 1 # get cmera values if img != None and len(obj_points) > 0 and len(img_points) > 0: return getCalibrationData(img, obj_points, img_points ) def cropImage(self, img=None): ''' Crops image if corners available @return: croped Image ''' if self.__corners != None and img != None and ( self._gui.getObj("chkCropImg").isChecked() or self._gui.getObj("chkCropImgManual").isChecked() ) : # default settings for manual crop try: borderX = int( str(self._gui.getObj("txtBorderLR").text()) ) borderY = int( str(self._gui.getObj("txtBorderTB").text()) ) except: borderX = 0 borderY = 0 xmin = (img.shape[1]-1)/2 - borderX xmax = (img.shape[1]-1)/2 + borderX ymin = (img.shape[0]-1)/2 - borderY ymax = (img.shape[0]-1)/2 + borderY # settings for automatic crop if self._gui.getObj("chkCropImg").isChecked(): border = str( self._gui.getObj("txtCalibrationBorders").text() ).replace(",", ".") try: borders = int( float(border)/100.0 ) except: borders = 0 borderX = int(img.shape[1] * borders) borderY = int(img.shape[0] * borders) xmin = int(self.__corners[0][0]) xmax = int(self.__corners[0][1]) ymin = int(self.__corners[1][0]) ymax = int(self.__corners[1][1]) # check new borders if xmin-borderX > 0: xmin = xmin-borderX else: xmin = 0 if ymin-borderY > 0: ymin = ymin-borderY else: ymin = 0 if xmax+borderX <= img.shape[1]: xmax = xmax+borderX else: xmax = img.shape[1]-1 if ymax+borderY <= img.shape[0]: ymax = ymax+borderY else: ymax = img.shape[0]-1 # conversion before if self._gui.getObj("chkCropConvBefore").isChecked(): img = cvtColor( img, COLOR_BGR2RGB ) # crop image try: img = img[ymin:ymax, xmin:xmax] # conversion after img = cvtColor( img, COLOR_BGR2RGB ) except: print "ERROR" return img def __saveImg(self): ''' Saves current image ''' if self.__imgScene != None: img = self.__imgScene # stop video active = self._imageGrabber.isActive() self._imageGrabber.stopVideo() # open file dialog options = copy(self._gui.dialogOptionsDef) options['type'] = self._gui.dialogTypes['FileSave'] options['filetypes'] = "JPG (*.jpg)" options['title'] = "Save current frame as" src = str( self._gui.dialog(options) ) # check filepath and save if len(src) > 0: if not src.endswith(".jpg"): src = src+".jpg" self._gui.status( "write to " + src ) cvtColor(img, COLOR_BGR2RGB) imwrite(src, img) # reset video streaming if active: self._imageGrabber.startVideo() def undistortImage(self, img=None): ''' Undistorts image @return: Image ''' if self.__camera_matrix != None and self.__dist_coefs != None and img != None: return undistortImg( img, self.__camera_matrix, self.__dist_coefs ) return img def __loadConfiguration(self): ''' Loads configuration ''' # stop video active = self._imageGrabber.isActive() self._imageGrabber.stopVideo() # get path options = copy(self._gui.dialogOptionsDef) options['filetypes'] = "config file (*cfg)" src = str( self._gui.dialog(options) ) if self.__loadConfigData(src): self._gui.status("Distortion config loaded.") # restore video streaming mode if active: self._imageGrabber.startVideo() def __loadConfigData(self, src): ''' Loads data from config file ''' if len(src) > 0 and isfile(src): # load file data = load( open(src, "rb") ) if 'camera_matrix' in data: self.__camera_matrix = data['camera_matrix'] if 'dist_coefs' in data: self.__dist_coefs = data['dist_coefs'] if 'corners' in data: self.__corners = data['corners'] if 'calibrated' in data: self.__calibrated = data['calibrated'] if 'cropmanual' in data: self._gui.getObj("chkCropImgManual").setChecked( data['cropmanual'] ) if 'cropauto' in data: self._gui.getObj("chkCropImg").setChecked( data['cropauto'] ) if 'cropBorderLR' in data: self._gui.getObj("txtBorderLR").setText( data['cropBorderLR'] ) if 'cropBorderTB' in data: self._gui.getObj("txtBorderTB").setText( data['cropBorderTB'] ) if 'cropauto' in data: self._gui.getObj("txtCalibrationBorders").setText( data['cropauto'] ) if 'squareSize' in data: self._gui.getObj("txtCalibrationSquareSize").setText( data['squareSize'] ) if 'calibFrames' in data: self._gui.getObj("txtCalibrationFrames").setText( data['calibFrames'] ) if 'patternX' in data: self._gui.getObj("txtPatternX").setText( data['patternX'] ) if 'patternY' in data: self._gui.getObj("txtPatternY").setText( data['patternY'] ) return True return False def __saveConfiguration(self): ''' Saves configuration ''' # stop video active = self._imageGrabber.isActive() self._imageGrabber.stopVideo() options = copy(self._gui.dialogOptionsDef) options['type'] = self._gui.dialogTypes['FileSave'] options['title'] = "Save configuration" options['filetypes'] = "Configuration (*cfg *mr)" src = str( self._gui.dialog(options) ) if len(src) > 0: # check path if not src.endswith(".cfg"): src += ".cfg" # save data to file data = {'camera_matrix': self.__camera_matrix, 'dist_coefs': self.__dist_coefs, 'corners': self.__corners, 'calibrated': self.__calibrated, 'cropmanual': self._gui.getObj("chkCropImgManual").isChecked(), 'cropauto:': self._gui.getObj("chkCropImg").isChecked(), 'cropBorder': str( self._gui.getObj("txtCalibrationBorders").text() ), 'cropBorderLR': str( self._gui.getObj("txtBorderLR").text() ), 'cropBorderTB': str( self._gui.getObj("txtBorderTB").text() ), 'squareSize': str( self._gui.getObj("txtCalibrationSquareSize").text() ), 'calibFrames': str( self._gui.getObj("txtCalibrationFrames").text() ), 'patternX': str( self._gui.getObj("txtPatternX").text() ), 'patternY': str( self._gui.getObj("txtPatternY").text() )} dump( data, open(src, "wb") ) self._gui.status("Configuration saved to: " + src) # restore video streaming mode if active: self._imageGrabber.startVideo() def _showImage(self): ''' Shows image ''' if not self.isCalibrated() or self.isCalibrating(): self._updateScene( self.__gview, self.__scene, self.__imgScene, convert=False, keepRatio=True )
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 TreeDialog(QDialog): def __init__(self): import treedialog QDialog.__init__(self) self.ui = treedialog.Ui_Dialog() self.ui.setupUi(self) self.ui.draw_buton.clicked.connect(self.new_anim) self.scene = QGraphicsScene() self.ui.image.setScene(self.scene) self.ui.image.setRenderHints(QPainter.HighQualityAntialiasing) def get_params(self): params = dict() params["branch_split"] = self.ui.branch_split.value() params["branch_after_range"] = (self.ui.branch_after_min.value(), self.ui.branch_after_max.value()) params["branch_split_var"] = self.ui.branch_split_var.value() params["gravity"] = self.ui.gravity.value() params["down_die_probability"] = self.ui.down_die_probability.value() params["down_damping_x"] = self.ui.down_damping_x.value() params["down_damping_y"] = self.ui.down_damping_x.value() params["start_branches"] = self.ui.start_branches.value() params["keep_central"] = self.ui.keep_central.value() params["color"] = QColor(self.ui.r.value() * 255, self.ui.g.value() * 255, self.ui.b.value() * 255) params["color_speed"] = self.ui.color_speed.value() params["painter_thickness"] = self.ui.painter_thickness.value() params["painter_generations"] = self.ui.painter_generations.value() start_rand = [random.uniform(-1, 1) * self.ui.v_start_var.value() for i in range(2)] params["v_start"] = complex(self.ui.v_start_x.value()+start_rand[0], self.ui.v_start_y.value()+start_rand[1]) return params def new_anim(self): image = None painter_id = random.randint(0, 2**32) self.active_painer = painter_id index = 0 every = self.ui.repaint.value() self.scene.clear() tree_count = self.ui.tree_count.value() need_spacing = 65 used_locations = [] for tree_index in range(tree_count): z_range = 80 base_z = random.uniform(-z_range, z_range) def make_base(): return complex(10 + random.uniform(-350 + 150*tree_count, 350 + 150*tree_count), base_z) def closest_distance_to_used(base): return min([np.abs(np.real(base - item)) for item in used_locations]) base_location = make_base() while not len(used_locations) == 0 and closest_distance_to_used(base_location) < need_spacing: base_location = make_base() used_locations.append(base_location) scale = 1.0 + 0.75 * ((z_range - base_z) / (2*z_range)) ** 2 self.tree = Tree(self.get_params(), base_location=base_location, scale=scale) for iteration in self.tree.grow_iterations(self.ui.generations.value(), yield_every=every): self.tree.draw(self.scene, incremental=True) self.ui.progress.setText("Working ... displayed frame: {0}".format(index)) gradient = QLinearGradient(self.scene.itemsBoundingRect().topLeft(), self.scene.itemsBoundingRect().bottomLeft()) gradient.setColorAt(0.4, QColor(0, 0, 0)) gradient.setColorAt(0, QColor(25, 25, 25)) self.scene.setBackgroundBrush(QBrush(gradient)) self.ui.image.repaint() QApplication.processEvents() index += every if self.active_painer != painter_id: return self.ui.image.fitInView(self.scene.itemsBoundingRect(), 1) d = GrassDrawer(self.ui.image) d.draw_some_grass(150 + 75*tree_count) #self.ui.image.fitInView(self.scene.itemsBoundingRect(), 1) self.ui.progress.setText("Done. Displayed frame: {0}".format(index))
class OWQualityControl(widget.OWWidget): name = "Quality Control" description = "Experiment quality control" icon = "../widgets/icons/QualityControl.svg" priority = 5000 inputs = [("Experiment Data", Orange.data.Table, "set_data")] outputs = [] DISTANCE_FUNCTIONS = [("Distance from Pearson correlation", dist_pcorr), ("Euclidean distance", dist_eucl), ("Distance from Spearman correlation", dist_spearman)] settingsHandler = SetContextHandler() split_by_labels = settings.ContextSetting({}) sort_by_labels = settings.ContextSetting({}) selected_distance_index = settings.Setting(0) def __init__(self, parent=None): super().__init__(parent) ## Attributes self.data = None self.distances = None self.groups = None self.unique_pos = None self.base_group_index = 0 ## GUI box = gui.widgetBox(self.controlArea, "Info") self.info_box = gui.widgetLabel(box, "\n") ## Separate By box box = gui.widgetBox(self.controlArea, "Separate By") self.split_by_model = itemmodels.PyListModel(parent=self) self.split_by_view = QListView() self.split_by_view.setSelectionMode(QListView.ExtendedSelection) self.split_by_view.setModel(self.split_by_model) box.layout().addWidget(self.split_by_view) self.split_by_view.selectionModel().selectionChanged.connect( self.on_split_key_changed) ## Sort By box box = gui.widgetBox(self.controlArea, "Sort By") self.sort_by_model = itemmodels.PyListModel(parent=self) self.sort_by_view = QListView() self.sort_by_view.setSelectionMode(QListView.ExtendedSelection) self.sort_by_view.setModel(self.sort_by_model) box.layout().addWidget(self.sort_by_view) self.sort_by_view.selectionModel().selectionChanged.connect( self.on_sort_key_changed) ## Distance box box = gui.widgetBox(self.controlArea, "Distance Measure") gui.comboBox(box, self, "selected_distance_index", items=[name for name, _ in self.DISTANCE_FUNCTIONS], callback=self.on_distance_measure_changed) self.scene = QGraphicsScene() self.scene_view = QGraphicsView(self.scene) self.scene_view.setRenderHints(QPainter.Antialiasing) self.scene_view.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.mainArea.layout().addWidget(self.scene_view) self.scene_view.installEventFilter(self) self._disable_updates = False self._cached_distances = {} self._base_index_hints = {} self.main_widget = None self.resize(800, 600) def clear(self): """Clear the widget state.""" self.data = None self.distances = None self.groups = None self.unique_pos = None with disable_updates(self): self.split_by_model[:] = [] self.sort_by_model[:] = [] self.main_widget = None self.scene.clear() self.info_box.setText("\n") self._cached_distances = {} def set_data(self, data=None): """Set input experiment data.""" self.closeContext() self.clear() self.error(0) self.warning(0) if data is not None: keys = self.get_suitable_keys(data) if not keys: self.error(0, "Data has no suitable feature labels.") data = None self.data = data if data is not None: self.on_new_data() def update_label_candidates(self): """Update the label candidates selection GUI (Group/Sort By views). """ keys = self.get_suitable_keys(self.data) with disable_updates(self): self.split_by_model[:] = keys self.sort_by_model[:] = keys def get_suitable_keys(self, data): """ Return suitable attr label keys from the data where the key has at least two unique values in the data. """ attrs = [attr.attributes.items() for attr in data.domain.attributes] attrs = reduce(operator.iadd, attrs, []) # in case someone put non string values in attributes dict attrs = [(str(key), str(value)) for key, value in attrs] attrs = set(attrs) values = defaultdict(set) for key, value in attrs: values[key].add(value) keys = [key for key in values if len(values[key]) > 1] return keys def selected_split_by_labels(self): """Return the current selected split labels. """ sel_m = self.split_by_view.selectionModel() indices = [r.row() for r in sel_m.selectedRows()] return [self.sort_by_model[i] for i in indices] def selected_sort_by_labels(self): """Return the current selected sort labels """ sel_m = self.sort_by_view.selectionModel() indices = [r.row() for r in sel_m.selectedRows()] return [self.sort_by_model[i] for i in indices] def selected_distance(self): """Return the selected distance function. """ return self.DISTANCE_FUNCTIONS[self.selected_distance_index][1] def selected_base_group_index(self): """Return the selected base group index """ return self.base_group_index def selected_base_indices(self, base_group_index=None): indices = [] for g, ind in self.groups: if base_group_index is None: label = group_label(self.selected_split_by_labels(), g) ind = [i for i in ind if i is not None] i = self._base_index_hints.get(label, ind[0] if ind else None) else: i = ind[base_group_index] indices.append(i) return indices def on_new_data(self): """We have new data and need to recompute all. """ self.closeContext() self.update_label_candidates() self.info_box.setText( "%s genes \n%s experiments" % (len(self.data), len(self.data.domain.attributes)) ) self.base_group_index = 0 keys = self.get_suitable_keys(self.data) self.openContext(keys) ## Restore saved context settings (split/sort selection) split_by_labels = self.split_by_labels sort_by_labels = self.sort_by_labels def select(model, selection_model, selected_items): """Select items in a Qt item model view """ all_items = list(model) try: indices = [all_items.index(item) for item in selected_items] except: indices = [] for ind in indices: selection_model.select(model.index(ind), QItemSelectionModel.Select) with disable_updates(self): select(self.split_by_view.model(), self.split_by_view.selectionModel(), split_by_labels) select(self.sort_by_view.model(), self.sort_by_view.selectionModel(), sort_by_labels) with widget_disable(self): self.split_and_update() def on_split_key_changed(self, *args): """Split key has changed """ with widget_disable(self): if not self._disable_updates: self.base_group_index = 0 self.split_by_labels = self.selected_split_by_labels() self.split_and_update() def on_sort_key_changed(self, *args): """Sort key has changed """ with widget_disable(self): if not self._disable_updates: self.base_group_index = 0 self.sort_by_labels = self.selected_sort_by_labels() self.split_and_update() def on_distance_measure_changed(self): """Distance measure has changed """ if self.data is not None: with widget_disable(self): self.update_distances() self.replot_experiments() def on_view_resize(self, size): """The view with the quality plot has changed """ if self.main_widget: current = self.main_widget.size() self.main_widget.resize(size.width() - 6, current.height()) self.scene.setSceneRect(self.scene.itemsBoundingRect()) def on_rug_item_clicked(self, item): """An ``item`` in the quality plot has been clicked. """ update = False sort_by_labels = self.selected_sort_by_labels() if sort_by_labels and item.in_group: ## The item is part of the group if item.group_index != self.base_group_index: self.base_group_index = item.group_index update = True else: if sort_by_labels: # If the user clicked on an background item it # invalidates the sorted labels selection with disable_updates(self): self.sort_by_view.selectionModel().clear() update = True index = item.index group = item.group label = group_label(self.selected_split_by_labels(), group) if self._base_index_hints.get(label, 0) != index: self._base_index_hints[label] = index update = True if update: with widget_disable(self): self.split_and_update() def eventFilter(self, obj, event): if obj is self.scene_view and event.type() == QEvent.Resize: self.on_view_resize(event.size()) return super().eventFilter(obj, event) def split_and_update(self): """ Split the data based on the selected sort/split labels and update the quality plot. """ split_labels = self.selected_split_by_labels() sort_labels = self.selected_sort_by_labels() self.warning(0) if not split_labels: self.warning(0, "No separate by label selected.") self.groups, self.unique_pos = \ exp.separate_by(self.data, split_labels, consider=sort_labels, add_empty=True) self.groups = sorted(self.groups.items(), key=lambda t: list(map(float_if_posible, t[0]))) self.unique_pos = sorted(self.unique_pos.items(), key=lambda t: list(map(float_if_posible, t[0]))) if self.groups: if sort_labels: group_base = self.selected_base_group_index() base_indices = self.selected_base_indices(group_base) else: base_indices = self.selected_base_indices() self.update_distances(base_indices) self.replot_experiments() def get_cached_distances(self, measure): if measure not in self._cached_distances: attrs = self.data.domain.attributes mat = numpy.zeros((len(attrs), len(attrs))) self._cached_distances[measure] = \ (mat, set(zip(range(len(attrs)), range(len(attrs))))) return self._cached_distances[measure] def get_cached_distance(self, measure, i, j): matrix, computed = self.get_cached_distances(measure) key = (i, j) if i < j else (j, i) if key in computed: return matrix[i, j] else: return None def get_distance(self, measure, i, j): d = self.get_cached_distance(measure, i, j) if d is None: vec_i = take_columns(self.data, [i]) vec_j = take_columns(self.data, [j]) d = measure(vec_i, vec_j) mat, computed = self.get_cached_distances(measure) mat[i, j] = d key = key = (i, j) if i < j else (j, i) computed.add(key) return d def store_distance(self, measure, i, j, dist): matrix, computed = self.get_cached_distances(measure) key = (i, j) if i < j else (j, i) matrix[j, i] = matrix[i, j] = dist computed.add(key) def update_distances(self, base_indices=()): """Recompute the experiment distances. """ distance = self.selected_distance() if base_indices == (): base_group_index = self.selected_base_group_index() base_indices = [ind[base_group_index] \ for _, ind in self.groups] assert(len(base_indices) == len(self.groups)) base_distances = [] attributes = self.data.domain.attributes pb = gui.ProgressBar(self, len(self.groups) * len(attributes)) for (group, indices), base_index in zip(self.groups, base_indices): # Base column of the group if base_index is not None: base_vec = take_columns(self.data, [base_index]) distances = [] # Compute the distances between base column # and all the rest data columns. for i in range(len(attributes)): if i == base_index: distances.append(0.0) elif self.get_cached_distance(distance, i, base_index) is not None: distances.append(self.get_cached_distance(distance, i, base_index)) else: vec_i = take_columns(self.data, [i]) dist = distance(base_vec, vec_i) self.store_distance(distance, i, base_index, dist) distances.append(dist) pb.advance() base_distances.append(distances) else: base_distances.append(None) pb.finish() self.distances = base_distances def replot_experiments(self): """Replot the whole quality plot. """ self.scene.clear() labels = [] max_dist = numpy.nanmax(list(filter(None, self.distances))) rug_widgets = [] group_pen = QPen(Qt.black) group_pen.setWidth(2) group_pen.setCapStyle(Qt.RoundCap) background_pen = QPen(QColor(0, 0, 250, 150)) background_pen.setWidth(1) background_pen.setCapStyle(Qt.RoundCap) main_widget = QGraphicsWidget() layout = QGraphicsGridLayout() attributes = self.data.domain.attributes if self.data is not None: for (group, indices), dist_vec in zip(self.groups, self.distances): indices_set = set(indices) rug_items = [] if dist_vec is not None: for i, attr in enumerate(attributes): # Is this a within group distance or background in_group = i in indices_set if in_group: rug_item = ClickableRugItem(dist_vec[i] / max_dist, 1.0, self.on_rug_item_clicked) rug_item.setPen(group_pen) tooltip = experiment_description(attr) rug_item.setToolTip(tooltip) rug_item.group_index = indices.index(i) rug_item.setZValue(rug_item.zValue() + 1) else: rug_item = ClickableRugItem(dist_vec[i] / max_dist, 0.85, self.on_rug_item_clicked) rug_item.setPen(background_pen) tooltip = experiment_description(attr) rug_item.setToolTip(tooltip) rug_item.group = group rug_item.index = i rug_item.in_group = in_group rug_items.append(rug_item) rug_widget = RugGraphicsWidget(parent=main_widget) rug_widget.set_rug(rug_items) rug_widgets.append(rug_widget) label = group_label(self.selected_split_by_labels(), group) label_item = QGraphicsSimpleTextItem(label, main_widget) label_item = GraphicsSimpleTextLayoutItem(label_item, parent=layout) label_item.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) labels.append(label_item) for i, (label, rug_w) in enumerate(zip(labels, rug_widgets)): layout.addItem(label, i, 0, Qt.AlignVCenter) layout.addItem(rug_w, i, 1) layout.setRowMaximumHeight(i, 30) main_widget.setLayout(layout) self.scene.addItem(main_widget) self.main_widget = main_widget self.rug_widgets = rug_widgets self.labels = labels self.on_view_resize(self.scene_view.size())
class CoLocation(QMainWindow, Ui_MainWindow): flag = True categories = {} valid_images = ["jpg","png","tga", "pgm", "jpeg"] valid_videos = ["mp4", "avi"] edge_threshold = 100 to_disp = [] def __init__(self, ): super(CoLocation, self).__init__() #initialise from the ui designed by Designer App self.setupUi(self) self.setupUi_custom() def update_categories(self): #update selected categories for radiobox in self.findChildren(QtGui.QRadioButton): self.categories[radiobox.text()] = radiobox.isChecked() def setupUi_custom(self,): self.scene = QGraphicsScene() self.scene2 = QGraphicsScene() #TODO [WEIRD PROBLEM] QPixmap needs to be called at least once with JPG image before tensorFlow, otherwise program crashes self.scene.addPixmap(QPixmap(os.getcwd()+"/demo.jpg").scaled(self.graphicsView.size(), QtCore.Qt.KeepAspectRatio)) self.graphicsView.setScene(self.scene) import Yolo_module as yolo self.classifier = yolo.YOLO_TF() #Create thread for heavy processing and tensorflow, pass the instance of itself to modify GUI self.image_thread = ImageThread(self, self.classifier) #add connect SIGNAL here self.pushButton.clicked.connect(self.selectFile) self.horizontalSlider.valueChanged.connect(self.updateLCD) self.pushButton_2.clicked.connect(self.image_thread.disp_graph) self.pushButton_3.clicked.connect(self.selectFile_from_folder) #Add blank canvas initially fig1 = Figure() self.addmpl(fig1) def updateLCD(self): #update edge_threshold variable based on slider self.edge_threshold = self.horizontalSlider.value() self.lcdNumber.display(self.edge_threshold) def selectFile(self): #Clear previous image displays self.scene.clear() self.scene2.clear() self.update_categories() filename = QFileDialog.getOpenFileName(directory = '/home/yash/Downloads/Pascal VOC 2012/samples') self.lineEdit.setText(filename) if filename.split('.')[1] in self.valid_videos: self.image_thread.temp = filename #disp_video(filename) self.image_thread.start() elif filename.split('.')[1] in self.valid_images: self.image_thread.disp_img(filename = filename) self.image_thread.disp_graph() else: print("Invalid file format") def selectFile_from_folder(self): #Read all the images in the folder path = QFileDialog.getExistingDirectory(None, 'Select a folder:', '/home/yash/Downloads/Pascal VOC 2012', QtGui.QFileDialog.ShowDirsOnly) self.lineEdit_2.setText(path) for f in os.listdir(path): #list all the files in the folder ext = f.split('.')[1] #get the file extension if ext.lower() not in self.valid_images: #check if the extension is valid for the image continue filename = path+'/'+f #create the path of the image print(filename) self.image_thread.tag_image(filename, batch = True) #clear the image regions during batch upload self.scene.clear() self.scene2.clear() self.image_thread.disp_graph(batch = True) def addmpl(self, fig): #Add figure to canvas and widget self.canvas = FigureCanvas(fig) self.mplvl.addWidget(self.canvas) self.canvas.draw() def rmmpl(self,): #remove the canvas and widget self.mplvl.removeWidget(self.canvas) self.canvas.close()
class QtImageViewer(QGraphicsView): """ PyQt image viewer widget for a QPixmap in a QGraphicsView scene with mouse zooming and panning. Displays a QImage or QPixmap (QImage is internally converted to a QPixmap). To display any other image format, you must first convert it to a QImage or QPixmap. Some useful image format conversion utilities: qimage2ndarray: NumPy ndarray <==> QImage (https://github.com/hmeine/qimage2ndarray) ImageQt: PIL Image <==> QImage (https://github.com/python-pillow/Pillow/blob/master/PIL/ImageQt.py) """ # Mouse button signals emit image scene (x, y) coordinates. # !!! For image (row, column) matrix indexing, row = y and column = x. hover = pyqtSignal(float, float) leftMouseButtonPressed = pyqtSignal(float, float, object) rightMouseButtonPressed = pyqtSignal(float, float) leftMouseButtonReleased = pyqtSignal(float, float) leftMouseButtonDoubleClicked = pyqtSignal(float, float) rightMouseButtonDoubleClicked = pyqtSignal(float, float) areaSelected = pyqtSignal(float, float, float, float) pixelSelected = pyqtSignal(float, float) def __init__(self, parent=None, center=None, thumbnail=False): QGraphicsView.__init__(self, parent) # Image is displayed as a QPixmap in a QGraphicsScene attached to this QGraphicsView. self.scene = QGraphicsScene() self.setScene(self.scene) # Store a local handle to the scene's current image pixmap. self._pixmapHandle = None # Image aspect ratio mode. # !!! ONLY applies to full image. Aspect ratio is always ignored when zooming. # Qt.IgnoreAspectRatio: Scale image to fit viewport. # Qt.KeepAspectRatio: Scale image to fit inside viewport, preserving aspect ratio. # Qt.KeepAspectRatioByExpanding: Scale image to fill the viewport, preserving aspect ratio. self.aspectRatioMode = Qt.KeepAspectRatio # Scroll bar behaviour. # Qt.ScrollBarAlwaysOff: Never shows a scroll bar. # Qt.ScrollBarAlwaysOn: Always shows a scroll bar. # Qt.ScrollBarAsNeeded: Shows a scroll bar only when zoomed. self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # Stack of QRectF zoom boxes in scene coordinates. self.zoomStack = [] self.dragSelect = False # Flags for enabling/disabling mouse interaction. self.canZoom = True self.canPan = True self.center = center self.thumbnail = thumbnail def hasImage(self): """ Returns whether or not the scene contains an image pixmap. """ return self._pixmapHandle is not None def clearImage(self): """ Removes the current image pixmap from the scene if it exists. """ if self.hasImage(): self.scene.removeItem(self._pixmapHandle) self.scene.clear() self._pixmapHandle = None def pixmap(self): """ Returns the scene's current image pixmap as a QPixmap, or else None if no image exists. :rtype: QPixmap | None """ if self.hasImage(): return self._pixmapHandle.pixmap() return None def image(self): """ Returns the scene's current image pixmap as a QImage, or else None if no image exists. :rtype: QImage | None """ if self.hasImage(): return self._pixmapHandle.pixmap().toImage() return None def setImage(self, image): """ Set the scene's current image pixmap to the input QImage or QPixmap. Raises a RuntimeError if the input image has type other than QImage or QPixmap. :type image: QImage | QPixmap """ if type(image) is QPixmap: pixmap = image elif type(image) is QImage: pixmap = QPixmap.fromImage(image) else: raise RuntimeError( "ImageViewer.setImage: Argument must be a QImage or QPixmap.") if self.hasImage(): self._pixmapHandle.setPixmap(pixmap) else: self._pixmapHandle = self.scene.addPixmap(pixmap) self.setSceneRect(QRectF( pixmap.rect())) # Set scene size to image size. self.updateViewer() def loadImageFromFile(self, fileName=""): """ Load an image from file. Without any arguments, loadImageFromFile() will popup a file dialog to choose the image file. With a fileName argument, loadImageFromFile(fileName) will attempt to load the specified image file directly. """ if len(fileName) == 0: if QT_VERSION_STR[0] == '4': fileName = QFileDialog.getOpenFileName(self, "Open image file.") elif QT_VERSION_STR[0] == '5': fileName, dummy = QFileDialog.getOpenFileName( self, "Open image file.") if len(fileName) and os.path.isfile(fileName): image = QImage(fileName) self.setImage(image) def updateViewer(self): """ Show current zoom (if showing entire image, apply current aspect ratio mode). """ if not self.hasImage(): return if len(self.zoomStack) and self.sceneRect().contains( self.zoomStack[-1]): self.fitInView(self.zoomStack[-1], Qt.IgnoreAspectRatio ) # Show zoomed rect (ignore aspect ratio). else: self.zoomStack = [ ] # Clear the zoom stack (in case we got here because of an invalid zoom). if self.thumbnail == True: self.fitInView( self.sceneRect(), self.aspectRatioMode ) # Show entire image (use current aspect ratio mode). def resizeEvent(self, event): """ Maintain current zoom on resize. """ self.updateViewer() def mouseMoveEvent(self, event): if self.hasImage(): scenePos = self.mapToScene(event.pos()) self.hover.emit(scenePos.x(), scenePos.y()) if event.buttons() == Qt.RightButton: self.rightMouseButtonPressed.emit(scenePos.x(), scenePos.y()) else: pass QGraphicsView.mouseMoveEvent(self, event) def mousePressEvent(self, event): """ Start mouse pan or zoom mode. """ scenePos = self.mapToScene(event.pos()) if event.button() == Qt.LeftButton: if self.canPan: self.setDragMode(QGraphicsView.ScrollHandDrag) if self.hasImage(): self.leftMouseButtonPressed.emit(scenePos.x(), scenePos.y(), self) elif event.button() == Qt.RightButton: if self.dragSelect: if self.hasImage(): self.setDragMode(QGraphicsView.RubberBandDrag) self.viewport().setCursor(QCursor(Qt.CrossCursor)) self.rightMouseButtonPressed.emit(scenePos.x(), scenePos.y()) QGraphicsView.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ Stop mouse pan or zoom mode (apply zoom if valid). """ QGraphicsView.mouseReleaseEvent(self, event) scenePos = self.mapToScene(event.pos()) if event.button() == Qt.LeftButton: self.setDragMode(QGraphicsView.NoDrag) if self.hasImage(): self.leftMouseButtonReleased.emit(scenePos.x(), scenePos.y()) elif event.button() == Qt.RightButton: self.setDragMode(QGraphicsView.NoDrag) if self.hasImage(): self.viewport().setCursor(QCursor(Qt.OpenHandCursor)) if self.dragSelect: viewBBox = self.zoomStack[-1] if len( self.zoomStack) else self.sceneRect() selectionBBox = self.scene.selectionArea().boundingRect( ).intersected(viewBBox) print(selectionBBox) self.areaSelected.emit(selectionBBox.x(), selectionBBox.y(), selectionBBox.width(), selectionBBox.height()) else: self.pixelSelected.emit(scenePos.x(), scenePos.y()) def mouseDoubleClickEvent(self, event): """ Show entire image. """ scenePos = self.mapToScene(event.pos()) if event.button() == Qt.LeftButton: self.leftMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y()) elif event.button() == Qt.RightButton: if self.canZoom: self.zoomStack = [] # Clear zoom stack. self.updateViewer() self.rightMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y()) QGraphicsView.mouseDoubleClickEvent(self, event) def wheelEvent(self, event): try: if self.thumbnail == True: return zoomInFactor = 1.2 zoomOutFactor = .8 # Zoom if event.angleDelta().y() > 0: zoomFactor = zoomInFactor else: zoomFactor = zoomOutFactor self.scale(zoomFactor, zoomFactor) # Get the new position newPos = self.mapToScene(event.pos()) self.centerOn(newPos) except Exception as e: logging.info(e) def zoomToArea(self, center, scale): if self.hasImage(): self.setTransform(QTransform()) pos = QPoint(center[0], center[1]) self.centerOn(pos) self.scale(scale, scale) def resetZoom(self): self.setTransform(QTransform()) self.fitInView(self.sceneRect(), self.aspectRatioMode ) # Show entire image (use current aspect ratio mode). def showEvent(self, event): self.resetZoom()
class ProfileGraphViewer( QWidget ): " Profiling results as a graph " escapePressed = pyqtSignal() def __init__( self, scriptName, params, reportTime, dataFile, stats, parent = None ): QWidget.__init__( self, parent ) self.__dataFile = dataFile self.__script = scriptName self.__reportTime = reportTime self.__params = params self.__stats = stats project = GlobalData().project if project.isLoaded(): self.__projectPrefix = os.path.dirname( project.fileName ) else: self.__projectPrefix = os.path.dirname( scriptName ) if not self.__projectPrefix.endswith( os.path.sep ): self.__projectPrefix += os.path.sep self.__createLayout() self.__getDiagramLayout() self.__viewer.setScene( self.__scene ) return def setFocus( self ): " Sets the focus properly " self.__viewer.setFocus() return def __isOutsideItem( self, fileName ): " Detects if the record should be shown as an outside one " return not fileName.startswith( self.__projectPrefix ) def __createLayout( self ): " Creates the widget layout " totalCalls = self.__stats.total_calls totalPrimitiveCalls = self.__stats.prim_calls # The calls were not induced via recursion totalTime = self.__stats.total_tt txt = "<b>Script:</b> " + self.__script + " " + self.__params.arguments + "<br>" \ "<b>Run at:</b> " + self.__reportTime + "<br>" + \ str( totalCalls ) + " function calls (" + \ str( totalPrimitiveCalls ) + " primitive calls) in " + \ FLOAT_FORMAT % totalTime + " CPU seconds" summary = QLabel( txt ) summary.setToolTip( txt ) summary.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Fixed ) summary.setFrameStyle( QFrame.StyledPanel ) summary.setAutoFillBackground( True ) summaryPalette = summary.palette() summaryBackground = summaryPalette.color( QPalette.Background ) summaryBackground.setRgb( min( summaryBackground.red() + 30, 255 ), min( summaryBackground.green() + 30, 255 ), min( summaryBackground.blue() + 30, 255 ) ) summaryPalette.setColor( QPalette.Background, summaryBackground ) summary.setPalette( summaryPalette ) self.__scene = QGraphicsScene() self.__viewer = DiagramWidget() self.__viewer.escapePressed.connect( self.__onESC ) vLayout = QVBoxLayout() vLayout.setContentsMargins( 0, 0, 0, 0 ) vLayout.setSpacing( 0 ) vLayout.addWidget( summary ) vLayout.addWidget( self.__viewer ) self.setLayout( vLayout ) return def __getDiagramLayout( self ): " Runs external tools to get the diagram layout " # Preparation: build a map of func ID -> fileName + line funcMap = {} index = 0 for func, props in self.__stats.stats.items(): funcMap[ index ] = ( func[ 0 ], func[ 1 ] ) index += 1 # First step is to run grpof2dot gprof2dot = thirdpartyDir + "gprof2dot" + os.path.sep + "gprof2dot.py" outputFile = self.__dataFile + ".dot" nodeLimit = Settings().profileNodeLimit edgeLimit = Settings().profileEdgeLimit dotSpec = safeRun( [ gprof2dot, '-n', str( nodeLimit ), '-e', str( edgeLimit ), '-f', 'pstats', '-o', outputFile, self.__dataFile ] ) graphDescr = safeRun( [ "dot", "-Tplain", outputFile ] ) graph = getGraphFromPlainDotData( graphDescr ) graph.normalize( self.physicalDpiX(), self.physicalDpiY() ) self.__scene.clear() self.__scene.setSceneRect( 0, 0, graph.width, graph.height ) for edge in graph.edges: self.__scene.addItem( FuncConnection( edge ) ) if edge.label != "": self.__scene.addItem( FuncConnectionLabel( edge ) ) for node in graph.nodes: fileName = "" lineNumber = 0 isOutside = True nodeID, newLabel = extractNodeID( node.label ) if nodeID != -1: node.label = newLabel # Now, detect the file name/line number and # if it belongs to the project ( fileName, lineNumber ) = funcMap[ nodeID ] self.__scene.addItem( Function( node, fileName, lineNumber, self.__isOutsideItem( fileName ) ) ) return def __onESC( self ): " Triggered when ESC is clicked " self.escapePressed.emit() return def onCopy( self ): " Copies the diagram to the exchange buffer " self.__viewer.onCopy() return def onSaveAs( self, fileName ): " Saves the diagram to a file " self.__viewer.onSaveAs( fileName ) return def zoomIn( self ): " Triggered on the 'zoom in' button " self.__viewer.zoomIn() return def zoomOut( self ): " Triggered on the 'zoom out' button " self.__viewer.zoomOut() return def resetZoom( self ): " Triggered on the 'zoom reset' button " self.__viewer.resetZoom() return
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 Canvas(QGraphicsView): def __init__(self, window, resultDict, imagePath): QGraphicsView.__init__(self) self.window = window self.pen = QPen(QColor("red")) self.pen.setWidth(0.5) self.canvasScene = QGraphicsScene() self.setScene(self.canvasScene) self.resultDict = resultDict self.imagePath = imagePath self.setBackgroundBrush(QBrush(Qt.black, Qt.SolidPattern)) def drawImage(self, imageFile): """Draw an image on the canvas""" image = QPixmap(imageFile) self.canvasScene.addPixmap(image) return image def drawFeaturePoint(self, pointList): """Draw a feature point on the canvas""" radius = 0.5 width, height = 2, 2 x1, y1, x2, y2 = pointList #Draw ellipse and bounding rect. Is a hacked version! self.canvasScene.addEllipse(x1 - radius + 5, y1 - radius + 3, 2 * radius, 2 * radius, self.pen) self.canvasScene.addEllipse(x2 - radius + self.imageWidth + 10, y2 - radius + 3, 2 * radius, 2 * radius, self.pen) self.canvasScene.addRect(x1 - width / 2. + 5, y1 - height / 2. + 3, width, height, self.pen) self.canvasScene.addRect(x2 - width / 2. + self.imageWidth + 10, y2 - height / 2. + 3, width, height, self.pen) def drawFeatureImages(self, imageFile): """Draw two consecutive images on the screen""" #Load image files path, file_ = os.path.split(imageFile) image1 = QPixmap(os.path.join(path, 'first_' + file_)) image2 = QPixmap(os.path.join(path, 'second_' + file_)) self.imageWidth = image1.width() #Add pixmaps image1Map = self.canvasScene.addPixmap(image1) image2Map = self.canvasScene.addPixmap(image2) #Shift pixmaps to the right position image1Map.setOffset(QPointF(5, 3)) image2Map.setOffset(QPointF(10 + image1.width(), 3)) def drawPolygon(self, Polygon): """Draw a polygon on the canvas""" polygon = QPolygonF() for point in Polygon: polygon.append(QPointF(point[0], point[1])) self.canvasScene.addPolygon(polygon, self.pen) def getWorkerId(self): return self.resultDict.values()[self.index][0][0] def getAssignmentId(self): return self.resultDict.keys()[self.index] def nextImage(self): """Load next image""" self.index += 1 self.canvasScene.clear() if self.index > len(self.resultDict) - 1 or len(self.resultDict) <= 0: self.canvasScene.addText("No annotations to review") self.window.reviewFlag = False self.window.updateTable() else: #Draw Image and Polygon assignmentId = self.resultDict.keys()[self.index] result = self.resultDict[assignmentId] image = result[0][1] pointList = result[0][2] if self.window.segmentation_mode: pointList = [round(float(point), 3) for point in pointList] pointList = zip(*[iter(pointList)] * 2) self.drawImage(os.path.join(self.imagePath, image)) self.drawPolygon(pointList) else: pointList = [round(float(point), 3) for point in pointList] pointList = zip(*[iter(pointList)] * 4) self.drawFeatureImages(os.path.join(self.imagePath, image)) for point in pointList: self.drawFeaturePoint(point) #update scene self.window.setWindowTitle("MTurk Review Tool ({0}/{1}) Rejected: {2} Approved: {3}".format(self.index + 1, len(self.resultDict), len(self.window.rejected), len(self.window.approved))) self.canvasScene.setSceneRect(self.canvasScene.itemsBoundingRect()) self.fitInView(0, 0, self.canvasScene.width(), self.canvasScene.height(), 1) self.canvasScene.update(0, 0, self.canvasScene.width(), self.canvasScene.height())
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 ConductorGraph(Plugin): _deferred_fit_in_view=Signal() _client_list_update_signal=Signal() def __init__(self, context): self._context=context super(ConductorGraph, self).__init__(context) self.initialised=False self.setObjectName('Conductor Graph') self._current_dotcode=None self._node_items=None self._edge_items=None self._node_item_events={} self._edge_item_events={} self._client_info_list={} self._widget=QWidget() self.cur_selected_client_name = "" self.pre_selected_client_name = "" # factory builds generic dotcode items self.dotcode_factory=PydotFactory() # self.dotcode_factory=PygraphvizFactory() self.dotcode_generator=RosGraphDotcodeGenerator() self.dot_to_qt=DotToQtGenerator() self._graph=ConductorGraphInfo() self._graph._reg_event_callback(self._update_client_list) self._graph._reg_period_callback(self._set_network_statisics) rospack=rospkg.RosPack() ui_file=os.path.join(rospack.get_path('concert_conductor_graph'), 'ui', 'conductor_graph.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('ConductorGraphUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene=QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) #self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('view-refresh')) self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('window-new')) self._widget.refresh_graph_push_button.pressed.connect(self._update_conductor_graph) self._widget.highlight_connections_check_box.toggled.connect(self._redraw_graph_view) self._widget.auto_fit_graph_check_box.toggled.connect(self._redraw_graph_view) self._widget.fit_in_view_push_button.setIcon(QIcon.fromTheme('zoom-original')) self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view) self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() self._widget.tabWidget.currentChanged.connect(self._change_client_tab) self._client_list_update_signal.connect(self._update_conductor_graph) #rospy.Subscriber(concert_msgs.Strings.CONCERT_CLIENT_CHANGES, ConcertClients, self._update_client_list) context.add_widget(self._widget) def restore_settings(self, plugin_settings, instance_settings): self.initialised=True self._refresh_rosgraph() def shutdown_plugin(self): pass def _update_conductor_graph(self): # re-enable controls customizing fetched ROS graph self._refresh_rosgraph() self._update_client_tab() def _refresh_rosgraph(self): if not self.initialised: return self._update_graph_view(self._generate_dotcode()) def _generate_dotcode(self): return self.dotcode_generator.generate_dotcode(rosgraphinst=self._graph, dotcode_factory=self.dotcode_factory, orientation='LR' ) def _update_graph_view(self, dotcode): #if dotcode==self._current_dotcode: # return self._current_dotcode=dotcode self._redraw_graph_view() def _update_client_list(self): print "[conductor graph]: _update_client_list" self._client_list_update_signal.emit() pass def _start_service(self,node_name,service_name): service=self._graph._client_info_list[node_name]['gateway_name']+"/"+service_name info_text='' if service_name=='status': service_handle=rospy.ServiceProxy(service, Status) call_result=service_handle() info_text="<html>" info_text +="<p>-------------------------------------------</p>" info_text +="<p><b>application_namespace: </b>" +call_result.application_namespace+"</p>" info_text +="<p><b>remote_controller: </b>" +call_result.remote_controller+"</p>" info_text +="<p><b>application_status: </b>" +call_result.application_status+"</p>" info_text +="</html>" self._client_list_update_signal.emit() elif service_name=='platform_info': service_handle=rospy.ServiceProxy(service, GetPlatformInfo) call_result=service_handle() info_text = "<html>" info_text += "<p>-------------------------------------------</p>" info_text += "<p><b>rocon_uri: </b>" + call_result.platform_info.uri + "</p>" info_text += "<p><b>concert_version: </b>" + call_result.platform_info.version + "</p>" info_text += "</html>" self._client_list_update_signal.emit() elif service_name=='invite': #sesrvice service_handle=rospy.ServiceProxy(service, Invite) #dialog dlg=QDialog(self._widget) dlg.setMinimumSize(400,0) dlg.setMaximumSize(400,0) dlg.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Expanding) #dialog layout ver_layout=QVBoxLayout(dlg) ver_layout.setContentsMargins (0,0,0,0) dynamic_arg=[] dynamic_arg.append(DynamicArgumentLayer(ver_layout,'Remote Target Name',False,[('remote_target_name','string')])) dynamic_arg.append(DynamicArgumentLayer(ver_layout,'Application Namespace',False,[('application_namespace','string')])) dynamic_arg.append(DynamicArgumentLayer(ver_layout,'Cancel',False,[('cancel','bool')])) #button button_hor_sub_widget=QWidget() button_hor_layout=QHBoxLayout(button_hor_sub_widget) btn_call=QPushButton("Call") btn_cancel=QPushButton("cancel") btn_call.clicked.connect(lambda: dlg.done(0)) btn_call.clicked.connect(lambda : self._call_invite_service(service,service_handle,dynamic_arg)) btn_cancel.clicked.connect(lambda: dlg.done(0)) #add button button_hor_layout.addWidget(btn_call) button_hor_layout.addWidget(btn_cancel) #add button layout ver_layout.addWidget(button_hor_sub_widget) dlg.setVisible(True) elif service_name=='start_app': #sesrvice service_handle=rospy.ServiceProxy(service, StartApp) #dialog dlg=QDialog(self._widget) dlg.setMinimumSize(400,0) dlg.setMaximumSize(400,0) dlg.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Expanding) #dialog layout ver_layout=QVBoxLayout(dlg) ver_layout.setContentsMargins (0,0,0,0) dynamic_arg=[] dynamic_arg.append(DynamicArgumentLayer(ver_layout,'Name',False,[('name','string')])) dynamic_arg.append(DynamicArgumentLayer(ver_layout,'Remappings',True,[('remap to','string'),('remap from','string')])) #button button_hor_sub_widget=QWidget() button_hor_layout=QHBoxLayout(button_hor_sub_widget) btn_call=QPushButton("Call") btn_cancel=QPushButton("cancel") btn_call.clicked.connect(lambda: dlg.done(0)) btn_call.clicked.connect(lambda : self._call_start_app_service(service,service_handle,dynamic_arg)) btn_cancel.clicked.connect(lambda: dlg.done(0)) #add button button_hor_layout.addWidget(btn_call) button_hor_layout.addWidget(btn_cancel) #add button layout ver_layout.addWidget(button_hor_sub_widget) dlg.setVisible(True) elif service_name=='stop_app': service_handle=rospy.ServiceProxy(service, StopApp) call_result=service_handle() info_text="<html>" info_text +="<p>-------------------------------------------</p>" info_text +="<p><b>stopped: </b>" +str(call_result.stopped)+"</p>" info_text +="<p><b>error_code: </b>" +str(call_result.error_code)+"</p>" info_text +="<p><b>message: </b>" +call_result.message+"</p>" info_text +="</html>" self._update_client_tab() else: print 'has no service' return # display the result of calling service # get tab widget handle service_text_widget=None cur_tab_widget=self._widget.tabWidget.currentWidget() if cur_tab_widget==None: return object_name='services_text_widget' for k in cur_tab_widget.children(): if k.objectName().count(object_name) >=1 : service_text_widget=k break if service_text_widget==None: return service_text_widget.clear() service_text_widget.appendHtml(info_text) def _call_invite_service(self,service,service_handle,dynamic_arg): remote_target_name="" application_namespace="" cancel=False for k in dynamic_arg: if k.name=='Remote Target Name': item_widget=k._get_param_list()[0][0][1] remote_target_name=item_widget.toPlainText() elif k.name=='Application Namespace': item_widgetwidget=k._get_param_list()[0][0][1] application_namespace=item_widget.toPlainText() elif k.name=='Cancel': item_widget=k._get_param_list()[0][0][1] cancel=item_widget.itemData(item_widget.currentIndex()) #calling service call_result=service_handle(remote_target_name,application_namespace,cancel) #status update self._client_list_update_signal.emit() # display the result of calling service info_text="<html>" info_text +="<p>-------------------------------------------</p>" info_text +="<p><b>result: </b>" +str(call_result.result)+"</p>" info_text +="<p><b>error_code: </b>" +str(call_result.error_code)+"</p>" info_text +="<p><b>message: </b>" +call_result.message+"</p>" info_text +="</html>" # get tab widget handle service_text_widget=None cur_tab_widget=self._widget.tabWidget.currentWidget() if cur_tab_widget==None: return object_name='services_text_widget' for k in cur_tab_widget.children(): if k.objectName().count(object_name) >=1 : service_text_widget=k break if service_text_widget==None: return service_text_widget.clear() service_text_widget.appendHtml(info_text) pass def _call_start_app_service(self,service,service_handle,dynamic_arg): name="" remappings=[] for k in dynamic_arg: if k.name=='Name': name=k._get_param_list()[0][0][1].toPlainText() elif k.name=='Remappings': for l in k._get_param_list(): remap_to=l[0][1].toPlainText() remap_from=l[1][1].toPlainText() remappings.append(Remapping(remap_to,remap_from)) #calling service call_result=service_handle(name,remappings) #status update self._client_list_update_signal.emit() # display the result of calling service info_text = '' info_text="<html>" info_text +="<p>-------------------------------------------</p>" info_text +="<p><b>started: </b>" +str(call_result.started)+"</p>" info_text +="<p><b>error_code: </b>" +str(call_result.error_code)+"</p>" info_text +="<p><b>message: </b>" +call_result.message+"</p>" info_text +="<p><b>app_namespace: </b>" +call_result.app_namespace+"</p>" info_text +="</html>" # get tab widget handle service_text_widget=None cur_tab_widget=self._widget.tabWidget.currentWidget() if cur_tab_widget==None: return object_name='services_text_widget' for k in cur_tab_widget.children(): if k.objectName().count(object_name) >=1 : service_text_widget=k break if service_text_widget==None: return service_text_widget.clear() service_text_widget.appendHtml(info_text) pass def _update_client_tab(self): print '[_update_client_tab]' self.pre_selected_client_name = self.cur_selected_client_name self._widget.tabWidget.clear() for k in self._graph._client_info_list.values(): main_widget=QWidget() ver_layout=QVBoxLayout(main_widget) ver_layout.setContentsMargins (9,9,9,9) ver_layout.setSizeConstraint (ver_layout.SetDefaultConstraint) #button layout sub_widget=QWidget() sub_widget.setAccessibleName('sub_widget') btn_grid_layout=QGridLayout(sub_widget) btn_grid_layout.setContentsMargins (9,9,9,9) btn_grid_layout.setColumnStretch (1, 0) btn_grid_layout.setRowStretch (2, 0) invite_btn=QPushButton("Invite") platform_info_btn=QPushButton("Get Platform Info") status_btn=QPushButton("Get Status") start_app_btn=QPushButton("Start App") stop_app_btn=QPushButton("Stop App") invite_btn.clicked.connect(lambda: self._start_service(self._widget.tabWidget.tabText(self._widget.tabWidget.currentIndex()),"invite")) platform_info_btn.clicked.connect(lambda: self._start_service(self._widget.tabWidget.tabText(self._widget.tabWidget.currentIndex()),"platform_info")) status_btn.clicked.connect(lambda: self._start_service(self._widget.tabWidget.tabText(self._widget.tabWidget.currentIndex()),"status")) start_app_btn.clicked.connect(lambda: self._start_service(self._widget.tabWidget.tabText(self._widget.tabWidget.currentIndex()),"start_app")) stop_app_btn.clicked.connect(lambda: self._start_service(self._widget.tabWidget.tabText(self._widget.tabWidget.currentIndex()),"stop_app")) btn_grid_layout.addWidget(invite_btn) btn_grid_layout.addWidget(platform_info_btn) btn_grid_layout.addWidget(status_btn) btn_grid_layout.addWidget(start_app_btn) btn_grid_layout.addWidget(stop_app_btn) ver_layout.addWidget(sub_widget) #client information layout context_label = QLabel() context_label.setText("Client information") ver_layout.addWidget(context_label) app_context_widget=QPlainTextEdit() app_context_widget.setObjectName(k["name"]+'_'+'app_context_widget') app_context_widget.setAccessibleName('app_context_widget') app_context_widget.appendHtml(k["app_context"]) app_context_widget.setReadOnly(True) cursor = app_context_widget.textCursor() cursor.movePosition(QTextCursor.Start,QTextCursor.MoveAnchor,0) app_context_widget.setTextCursor(cursor) ver_layout.addWidget(app_context_widget) #service layout context_label = QLabel() context_label.setText("Service result") ver_layout.addWidget(context_label) services_text_widget=QPlainTextEdit() services_text_widget.setObjectName(k["name"]+'_'+'services_text_widget') services_text_widget.setReadOnly(True) cursor = services_text_widget.textCursor() cursor.movePosition(QTextCursor.Start,QTextCursor.MoveAnchor,0) services_text_widget.setTextCursor(cursor) ver_layout.addWidget(services_text_widget) # new icon path="" if k["is_new"]==True: path=os.path.join(os.path.dirname(os.path.abspath(__file__)),"../../resources/images/new.gif") #add tab self._widget.tabWidget.addTab(main_widget,QIcon(path), k["name"]); #set previous selected tab for k in range(self._widget.tabWidget.count()): tab_text=self._widget.tabWidget.tabText(k) if tab_text == self.pre_selected_client_name: self._widget.tabWidget.setCurrentIndex(k) def _change_client_tab(self,index): self.cur_selected_client_name = self._widget.tabWidget.tabText(self._widget.tabWidget.currentIndex()) if self._widget.tabWidget.widget(index) !=None: for k in self._widget.tabWidget.widget(index).children(): if k.objectName().count("services_text_widget"): k.clear() pass def _set_network_statisics(self): if self._edge_items == None: return else: for edge_items in self._edge_items.itervalues(): for edge_item in edge_items: edge_dst_name=edge_item.to_node._label.text() edge_item.setToolTip(str(self._graph._client_info_list[edge_dst_name]['conn_stats'])) def _redraw_graph_view(self): self._scene.clear() self._node_item_events={} self._edge_item_events={} self._node_items=None self._edge_items=None if self._widget.highlight_connections_check_box.isChecked(): highlight_level=3 else: highlight_level=1 highlight_level=3 if self._widget.highlight_connections_check_box.isChecked() else 1 # layout graph and create qt items (nodes, edges)=self.dot_to_qt.dotcode_to_qt_items(self._current_dotcode, highlight_level=highlight_level, same_label_siblings=True) self._node_items=nodes self._edge_items=edges # if we wish to make special nodes, do that here (maybe subclass GraphItem, just like NodeItem does) #node for node_item in nodes.itervalues(): # set the color of conductor to orange if node_item._label.text()==self._graph._concert_conductor_name: royal_blue=QColor(65, 105, 255) node_item._default_color=royal_blue node_item.set_color(royal_blue) # redefine mouse event self._node_item_events[node_item._label.text()]=GraphEventHandler(self._widget.tabWidget,node_item,node_item.mouseDoubleClickEvent); node_item.mouseDoubleClickEvent=self._node_item_events[node_item._label.text()].NodeEvent; self._scene.addItem(node_item) #edge for edge_items in edges.itervalues(): for edge_item in edge_items: #redefine the edge hover event self._edge_item_events[edge_item._label.text()]=GraphEventHandler(self._widget.tabWidget,edge_item,edge_item._label.hoverEnterEvent); edge_item._label.hoverEnterEvent =self._edge_item_events[edge_item._label.text()].EdgeEvent; #self._edge_item_events[edge_item._label.text()]=GraphEventHandler(self._widget.tabWidget,edge_item,edge_item.mouseDoubleClickEvent); #edge_item.mouseDoubleClickEvent=self._edge_item_events[edge_item._label.text()].EdgeEvent; edge_item.add_to_scene(self._scene) #set the color of node as connection strength one of red, yellow, green edge_dst_name=edge_item.to_node._label.text() if edge_dst_name in self._graph._client_info_list.keys(): connection_strength=self._graph._client_info_list[edge_dst_name]['connection_strength'] if connection_strength=='very_strong': green=QColor(0, 255, 0) edge_item._default_color=green edge_item.set_color(green) elif connection_strength=='strong': green_yellow=QColor(125, 255,0) edge_item._default_color=green_yellow edge_item.set_color(green_yellow) elif connection_strength=='normal': yellow=QColor(238, 238,0) edge_item._default_color=yellow edge_item.set_color(yellow) elif connection_strength=='weak': yellow_red=QColor(255, 125,0) edge_item._default_color=yellow_red edge_item.set_color(yellow_red) elif connection_strength=='very_weak': red=QColor(255, 0,0) edge_item._default_color=red edge_item.set_color(red) #set the tooltip about network information edge_item.setToolTip(str(self._graph._client_info_list[edge_dst_name]['conn_stats'])) self._scene.setSceneRect(self._scene.itemsBoundingRect()) if self._widget.auto_fit_graph_check_box.isChecked(): self._fit_in_view() def _fit_in_view(self): self._widget.graphics_view.fitInView(self._scene.itemsBoundingRect(), Qt.KeepAspectRatio)
class FlowUIWidget( QWidget ): " The widget which goes along with the text editor " def __init__( self, editor, parent ): QWidget.__init__( self, parent ) # It is always not visible at the beginning because there is no # editor content at the start self.setVisible( False ) self.__editor = editor self.__parentWidget = parent self.__connected = False self.__needPathUpdate = False self.cflowSettings = getDefaultCflowSettings( self ) hLayout = QHBoxLayout() hLayout.setContentsMargins( 0, 0, 0, 0 ) hLayout.setSpacing( 0 ) vLayout = QVBoxLayout() vLayout.setContentsMargins( 0, 0, 0, 0 ) vLayout.setSpacing( 0 ) # Make pylint happy self.__toolbar = None self.__navBar = None self.__cf = None # Create the update timer self.__updateTimer = QTimer( self ) self.__updateTimer.setSingleShot( True ) self.__updateTimer.timeout.connect( self.process ) vLayout.addWidget( self.__createNavigationBar() ) vLayout.addWidget( self.__createGraphicsView() ) hLayout.addLayout( vLayout ) hLayout.addWidget( self.__createToolbar() ) self.setLayout( hLayout ) self.updateSettings() # Connect to the change file type signal mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager self.connect( editorsManager, SIGNAL( 'fileTypeChanged' ), self.__onFileTypeChanged ) return def __createToolbar( self ): " Creates the toolbar " self.__toolbar = QToolBar( self ) self.__toolbar.setOrientation( Qt.Vertical ) self.__toolbar.setMovable( False ) self.__toolbar.setAllowedAreas( Qt.RightToolBarArea ) self.__toolbar.setIconSize( QSize( 16, 16 ) ) self.__toolbar.setFixedWidth( 28 ) self.__toolbar.setContentsMargins( 0, 0, 0, 0 ) return self.__toolbar def __createNavigationBar( self ): " Creates the navigation bar " self.__navBar = ControlFlowNavigationBar( self ) return self.__navBar def __createGraphicsView( self ): """ Creates the graphics view """ self.scene = QGraphicsScene( self ) self.view = CFGraphicsView( self ) self.view.setScene( self.scene ) self.view.zoomTo( Settings().flowScale ) return self.view def process( self ): """ Parses the content and displays the results """ if not self.__connected: self.__connectEditorSignals() content = self.__editor.text() self.__cf = getControlFlowFromMemory( content ) if len( self.__cf.errors ) != 0: self.__navBar.updateInfoIcon( self.__navBar.STATE_BROKEN_UTD ) return self.__navBar.updateInfoIcon( self.__navBar.STATE_OK_UTD ) # if len( self.__cf.warnings ) != 0: # self.logMessage( "Parser warnings: " ) # for warn in self.__cf.warnings: # print str( warn[0] ) + ": " + warn[1] self.scene.clear() try: # Top level canvas has no adress and no parent canvas canvas = VirtualCanvas( self.cflowSettings, None, None, None ) canvas.layout( self.__cf ) canvas.setEditor( self.__editor ) width, height = canvas.render() self.scene.setSceneRect( 0, 0, width, height ) canvas.draw( self.scene, 0, 0 ) except Exception, exc: print "Exception:\n" + str( exc ) return
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 histogramDialog(QDialog, FORM_CLASS): def __init__(self, iface, parent=None): self.iface = iface self.plugin_dir = os.path.dirname(__file__) # Some constants self.HISTOGRAM = self.tr('Histogram') self.BROWSE = self.tr('Browse') self.CANCEL = self.tr('Cancel') self.CLOSE = self.tr('Close') self.OK = self.tr('OK') self.NUMBEROFRINGS = 10 # Number of concentric rings in the histogram """Constructor.""" super(histogramDialog, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) okButton = self.button_box.button(QDialogButtonBox.Ok) okButton.setText(self.OK) cancelButton = self.button_box.button(QDialogButtonBox.Cancel) cancelButton.setText(self.CANCEL) browseButton = self.BrowseButton browseButton.setText(self.BROWSE) closeButton = self.button_box.button(QDialogButtonBox.Close) closeButton.setText(self.CLOSE) # Connect signals okButton.clicked.connect(self.startWorker) cancelButton.clicked.connect(self.killWorker) closeButton.clicked.connect(self.reject) browseButton.clicked.connect(self.browse) #minvalSBCh = self.minValueSpinBox.valueChanged[str] #minvalSBCh.connect(self.updateBins) #minvalSBCh.connect(function ....) #binsSBCh = self.binsSpinBox.valueChanged[str] #binsSBCh.connect(self.updateBins) #self.iface.legendInterface().itemAdded.connect( # self.layerlistchanged) #self.iface.legendInterface().itemRemoved.connect( # self.layerlistchanged) inpIndexCh = self.InputLayer.currentIndexChanged['QString'] inpIndexCh.connect(self.layerchanged) fieldIndexCh = self.inputField.currentIndexChanged['QString'] fieldIndexCh.connect(self.fieldchanged) QObject.disconnect(self.button_box, SIGNAL("rejected()"), self.reject) # Set instance variables self.worker = None self.inputlayerid = None self.layerlistchanging = False self.bins = 8 self.binsSpinBox.setValue(self.bins) self.selectedFeaturesCheckBox.setChecked(True) self.scene = QGraphicsScene(self) self.histogramGraphicsView.setScene(self.scene) self.result = None def startWorker(self): #self.showInfo('Ready to start worker') # Get the input layer layerindex = self.InputLayer.currentIndex() layerId = self.InputLayer.itemData(layerindex) inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId) if inputlayer is None: self.showError(self.tr('No input layer defined')) return if inputlayer.featureCount() == 0: self.showError(self.tr('No features in input layer')) self.scene.clear() return self.bins = self.binsSpinBox.value() self.outputfilename = self.outputFile.text() self.minValue = self.minValueSpinBox.value() self.maxValue = self.maxValueSpinBox.value() if self.maxValue - self.minValue < 0: self.showError(self.tr('Max value less than min value')) return if self.inputField.count() == 0: self.showError(self.tr('Missing numerical field')) self.scene.clear() return fieldindex = self.inputField.currentIndex() fieldname = self.inputField.itemData(fieldindex) self.result = None # create a new worker instance worker = Worker(inputlayer, self.bins, self.minValue, self.maxValue, self.selectedFeaturesCheckBox.isChecked(), fieldname) ## configure the QgsMessageBar #msgBar = self.iface.messageBar().createMessage(self.tr('Joining'), '') #self.aprogressBar = QProgressBar() #self.aprogressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) #acancelButton = QPushButton() #acancelButton.setText(self.CANCEL) #acancelButton.clicked.connect(self.killWorker) #msgBar.layout().addWidget(self.aprogressBar) #msgBar.layout().addWidget(acancelButton) ## Has to be popped after the thread has finished (in ## workerFinished). #self.iface.messageBar().pushWidget(msgBar, # self.iface.messageBar().INFO) #self.messageBar = msgBar # start the worker in a new thread thread = QThread(self) worker.moveToThread(thread) worker.finished.connect(self.workerFinished) worker.error.connect(self.workerError) worker.status.connect(self.workerInfo) worker.progress.connect(self.progressBar.setValue) #worker.progress.connect(self.aprogressBar.setValue) thread.started.connect(worker.run) thread.start() self.thread = thread self.worker = worker self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) self.button_box.button(QDialogButtonBox.Close).setEnabled(False) self.InputLayer.setEnabled(False) self.inputField.setEnabled(False) def workerFinished(self, ok, ret): """Handles the output from the worker and cleans up after the worker has finished.""" # clean up the worker and thread self.worker.deleteLater() self.thread.quit() self.thread.wait() self.thread.deleteLater() # remove widget from the message bar (pop) #self.iface.messageBar().popWidget(self.messageBar) if ok and ret is not None: #self.showInfo("Histogram: " + str(ret)) self.result = ret # report the result # As a CSV file: if self.outputfilename != "": try: with open(self.outputfilename, 'wb') as csvfile: csvwriter = csv.writer(csvfile, delimiter=';', quotechar='"', quoting=csv.QUOTE_MINIMAL) csvwriter.writerow(["StartValue", "EndValue", "Number"]) for i in range(len(ret)-1): csvwriter.writerow([ret[i][0],ret[i+1][0], ret[i][1]]) csvwriter.writerow([ret[len(ret)-1][0],self.maxValue, ret[len(ret)-1][1]]) with open(self.outputfilename + 't', 'wb') as csvtfile: csvtfile.write('"Real","Real","Integer"') except IOError, e: self.showInfo("Trouble writing the CSV file: " + str(e)) # Draw the histogram self.drawHistogram() else:
class WsnViewer(QtGui.QMainWindow, Ui_WsnViewerUI): def __init__(self, parent=None): super(WsnViewer, self).__init__(parent) self.setupUi (self) self.m_nodeNumber = 10 self.m_maxRfRange = 70 self.m_macAddr = MacAddress () self.m_nodeLoc = Coordonate () self.m_nodeList = self.m_macAddr.GetListAddr(10) self.m_edgeList = 0 self.m_edgeDict = {} self.m_nodeLocDict = {} self.m_scene = QGraphicsScene (self.graphicsView) #self.m_paramWin = Ui_paramWindow () self.m_graph = nx.Graph() self.m_data = list () self.DataReader = Data () self.graphicsView.setDragMode (self.graphicsView.RubberBandDrag) self.graphicsView.setRenderHints (QPainter.Antialiasing | QPainter.SmoothPixmapTransform) self.graphicsView.setScene (self.m_scene) self.ConnectActions () def ConnectActions(self): self.actionQuit.triggered.connect (QtGui.qApp.quit) self.actionOpen.triggered.connect (self.OpenWsnTopology) self.actionRandom_topology.triggered.connect (self.GenerateRandWsn) self.actionTools.triggered.connect(self.SetRadioRange) self.actionSave.triggered.connect(self.Save) def OpenWsnTopology (self): fileName = QtGui.QFileDialog.getOpenFileName( self, "Ouvrir un fichier des positions des noeuds", QtCore.QDir.homePath(), "Fichiers texte (*.txt)" ) if (fileName): self.m_data = self.DataReader.ReadFile(fileName) def GenerateRandWsn (self): self.m_nodeList = self.m_macAddr.GetListAddr(self.m_nodeNumber) #print(self.m_nodeList) self.m_edgeList, self.m_nodeLocDict = self.m_nodeLoc.EdgeCreate (self.m_nodeList) #print(self.m_nodeLocDict) #print(self.m_edgeList) self.m_scene.clear() self.DrawGraph () def main (self): self.show() def OpenDialog(self): self.dlg = OpenFileDialog () self.dlg.show() def DrawGraph (self): for edge in self.m_edgeList: self.m_edgeDict [edge] = EdgeItem (self.m_nodeLocDict, edge[0], edge[1]) self.m_scene.addItem(self.m_edgeDict [edge]) for node in self.m_nodeLocDict.iterkeys(): nodeItem = NodeItem (self.m_scene, self.m_nodeLocDict, node) #nodeItem.m_signalLinkNode.nodeItemSignal.connect (self.UpdateNodeLocDict) self.m_scene.addItem (nodeItem) def Save (self): filename = QtGui.QFileDialog.getSaveFileName ( self, "Ouvrir un fichier des positions des noeuds", QtCore.QDir.homePath(), "Fichiers texte (*.txt)" ) if self.m_edgeList and filename: self.DataReader.WriteWSn(self.m_edgeList, self.m_nodeLocDict, filename) def UpdateNodeLocDict (self, nodeName, nodePos): self.m_nodeLocDict [nodeName] = nodePos for node, pos in self.m_nodeLocDict.items(): if node != nodeName: edge = (nodeName, node) if self.Distance(nodePos, pos) <= self.m_maxRfRange: if not edge in self.m_edgeList and not edge[::-1] in self.m_edgeList: self.m_edgeList.append (edge) self.m_edgeDict [edge] = EdgeItem (self.m_nodeLocDict, edge[0], edge[1]) self.m_scene.addItem(self.m_edgeDict [edge]) #print ("%s %s %s" % (node, pos[0], pos[1])) else: self.RemoveLink (edge) self.UpdateNodeList (edge) #print ("%s %s %s" % (node, pos[0], pos[1])) def UpdateNodeList (self, edge): while edge in self.m_edgeList: self.m_edgeList.remove (edge) #while edge[::-1] in self.m_edgeList: # self.m_edgeList.remove (edge[::-1]) def RemoveLink (self, edge): if edge in self.m_edgeDict: self.m_scene.removeItem (self.m_edgeDict [edge]) del self.m_edgeDict [edge] self.m_scene.update() print ("%s %s" % (edge[0], edge[1])) def UpdateScene (self, edge): self.m_scene.addItem(EdgeItem (self.m_nodeLocDict, edge[0], edge[1])) def Distance (self, u, v): x0, y0 = u x1, y1 = v return math.sqrt((x0 - x1)**2 + (y0 - y1)**2) def SetRadioRange (self): self.rfWindow = RfSettingWindow () resultat = self.rfWindow.exec_() if resultat: self.rfWindow.SetRadioValues () self.m_nodeNumber = self.rfWindow.GetNodeNumber () self.m_maxRfRange = self.rfWindow.GetRfRange () self.GenerateRandWsn ()
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 pageView(QGraphicsView): def __init__(self, wpage): QGraphicsView.__init__(self) self.init(wpage) self.initShape() # self.selection = pageSelection(self.heditor) def init(self, wpage): self.wpage = wpage self.heditor = wpage.heditor self.filesize = self.heditor.filesize self.start = True self.pagew = 20 self.pageh = 20 self.pageItems = [] self.offsetItems = [] self.displayLines = 0 def initShape(self): #Scene self.scene = QGraphicsScene() self.setScene(self.scene) #Font self.initFont() #Headers self.setHeads(self.heditor.pagesPerBlock) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setAlignment(Qt.AlignLeft) def initFont(self): self.font = QFont("Gothic") self.font.setFixedPitch(1) self.font.setBold(False) self.font.setPixelSize(14) def setHeads(self, pagesPerBlock): if self.heditor.pageOffView: self.setOffsetHead() else: self.setBlockHead() self.setPageHead(self.heditor.pagesPerBlock) linesize = 95 + (self.heditor.pagesPerBlock * (self.pagew + 2)) #Decoration headLine = QGraphicsLineItem(QLineF(0, 20, linesize, 20)) self.scene.addItem(headLine) headOffLine = QGraphicsLineItem(QLineF(90, 0, 90, 700)) self.scene.addItem(headOffLine) def setOffsetHead(self): self.offHead = QGraphicsTextItem() self.offHead.setDefaultTextColor(QColor(Qt.red)) self.offHead.setFont(self.font) self.offHead.setPlainText("Offset(Kb)") self.offHead.setPos(5, 0) self.scene.addItem(self.offHead) def setPageHead(self, len): count = 0 x = 95 while count < len: item = QGraphicsSimpleTextItem() item.setFont(self.font) item.setText("%.2x" % count) item.setPos(x, 3) self.scene.addItem(item) x += self.pagew + 2 count += 1 def setBlockHead(self): self.blockHead = QGraphicsTextItem() self.blockHead.setDefaultTextColor(QColor(Qt.red)) self.blockHead.setFont(self.font) self.blockHead.setPlainText("Block") self.blockHead.setPos(15, 0) self.scene.addItem(self.blockHead) def initOffsetItems(self): count = 0 x = 0 y = 25 while count <= self.displayLines: item = QGraphicsTextItem() item.setDefaultTextColor(QColor(Qt.red)) item.setFont(self.font) item.setPos(x, y) self.offsetItems.append(item) y += self.pageh + 2 count += 1 #Add Items in scene for item in self.offsetItems: self.scene.addItem(item) def initPageItems(self): id = 0 countpage = 0 startx = 95 starty = 25 x = startx y = starty line = 0 while line <= self.displayLines: while countpage < self.heditor.pagesPerBlock: p = page(x, y, id, self) self.pageItems.append(p) id += 1 # self.scene.addItem(sec) x += self.pagew + 2 countpage += 1 x = startx y += self.pageh + 2 countpage = 0 line += 1 #Add items in scene for item in self.pageItems: self.scene.addItem(item) def hidePageItems(self, startid): end = len(self.pageItems) for item in self.pageItems[startid:end]: item.setVisible(False) def setAllPageItemsVisible(self): for item in self.pageItems: item.setVisible(True) def hideOffsetItems(self, startid): end = len(self.offsetItems) for item in self.offsetItems[startid:end]: item.setVisible(False) def setAllOffsetItemsVisible(self): for item in self.offsetItems: item.setVisible(True) def appendOffsetItems(self, linesToAppend): count = 0 x = 0 y = 25 + (len(self.offsetItems) * (self.pageh + 2)) # print "Y append offset ", y while count <= linesToAppend: item = QGraphicsTextItem() item.setDefaultTextColor(QColor(Qt.red)) item.setFont(self.font) item.setPos(x, y) self.offsetItems.append(item) self.scene.addItem(item) y += self.pageh + 2 count += 1 def appendPageItems(self, linesToAppend): count = 0 cp = 0 x = 95 y = 25 + ((len(self.pageItems) / self.heditor.pagesPerBlock) * (self.pageh + 2)) id = len(self.pageItems) while count <= linesToAppend: while cp < self.heditor.pagesPerBlock: item = page(x, y, id, self) self.pageItems.append(item) self.scene.addItem(item) id += 1 x += self.pagew + 2 cp += 1 count += 1 x = 95 y += self.pageh + 2 def refreshOffsetItems(self, offset): #Check if end of pages or if number of pages < display pages self.setAllOffsetItemsVisible() block = (offset / self.heditor.pageSize) / self.heditor.pagesPerBlock startBlockOffset = block * (self.heditor.pagesPerBlock * self.heditor.pageSize) lineToDisplay = ((self.filesize - offset) / self.heditor.pageSize) / self.heditor.pagesPerBlock if ((self.filesize - offset) / self.heditor.pageSize) % self.heditor.pagesPerBlock > 0: lineToDisplay += 1 if lineToDisplay >= self.displayLines: offset = startBlockOffset for item in self.offsetItems[0:self.displayLines]: if self.heditor.decimalview: if self.heditor.pageOffView: offlabel = QString("%.10d" % (offset / 1024)) else: offlabel = QString("%.10d" % (offset / (self.heditor.pageSize * self.heditor.pagesPerBlock))) else: if self.heditor.pageOffView: offlabel = QString("%.10x" % (offset / 1024)) else: offlabel = QString("%.10x" % (offset / (self.heditor.pageSize * self.heditor.pagesPerBlock))) item.setPlainText(offlabel) offset = offset + (self.heditor.pagesPerBlock * self.heditor.pageSize) self.heditor.startBlockOffset = startBlockOffset else: if lineToDisplay == 0: lineToDisplay = 5 offset = startBlockOffset - (lineToDisplay * self.heditor.pagesPerBlock * self.heditor.pageSize) if ((self.filesize - offset) / self.heditor.pageSize) % self.heditor.pagesPerBlock > 0: lineToDisplay += 1 self.heditor.startBlockOffset = offset for item in self.offsetItems[0:lineToDisplay]: if self.heditor.decimalview: if self.heditor.pageOffView: offlabel = QString("%.10d" % (offset / 1024)) else: offlabel = QString("%.10d" % (offset / (self.heditor.pageSize * self.heditor.pagesPerBlock))) else: if self.heditor.pageOffView: offlabel = QString("%.10x" % (offset / 1024)) else: offlabel = QString("%.10x" % (offset / (self.heditor.pageSize * self.heditor.pagesPerBlock))) item.setPlainText(offlabel) offset = offset + (self.heditor.pagesPerBlock * self.heditor.pageSize) self.hideOffsetItems(lineToDisplay) def refreshPageItems(self, offset): self.setAllPageItemsVisible() maxpages = self.displayLines * self.heditor.pagesPerBlock displaypages = (self.filesize - offset) / self.heditor.pageSize if displaypages <= maxpages: if displaypages == 0: startline = self.lines - 5 startOffset = startline * (self.heditor.pageSize * self.heditor.pagesPerBlock) rangeOffset = self.filesize - startOffset newdisplaypages = rangeOffset / self.heditor.pageSize if rangeOffset % self.heditor.pageSize > 0: newdisplaypages += 1 self.hidePageItems(newdisplaypages) self.heditor.startBlockOffset = startOffset else: rangeOffset = self.filesize - offset rangePages = rangeOffset / self.heditor.pageSize rangeLines = rangePages / self.heditor.pagesPerBlock newdisplaypages = rangeOffset / self.heditor.pageSize if rangeOffset % self.heditor.pageSize > 0: newdisplaypages += 1 self.hidePageItems(newdisplaypages) self.heditor.startBlockOffset = offset else: self.heditor.startBlockOffset = offset self.heditor.pageselection.update() def refreshAllContent(self): self.scene.clear() del self.offsetItems[:] del self.pageItems[:] self.setHeads(self.heditor.pagesPerBlock) self.initOffsetItems() self.initPageItems() self.refreshOffsetItems(self.heditor.startBlockOffset) self.refreshPageItems(self.heditor.startBlockOffset) def lineToOffset(self, line): offset = (line * (self.heditor.pagesPerBlock * self.heditor.pageSize)) return offset def lineToOffsetKb(self, line): offset = (line * (self.heditor.pagesPerBlock * self.heditor.pageSize)) / 1024 return offset def lineToOffsetMb(self, line): offset = ((line * (self.heditor.pagesPerBlock * self.heditor.pageSize)) / 1024) / 1024 return offset def lineToOffsetGb(self, line): offset = (((line * (self.heditor.pagesPerBlock * self.heditor.pageSize)) / 1024) / 1024) / 1024 return offset ############################ # Colorize Pages # ############################ def refreshPagesColor(self, id): # print "Refresh: ", id self.cleanSelection() self.pageItems[id].setBrush(QBrush(Qt.green, Qt.SolidPattern)) def cleanSelection(self): item = self.pageItems[self.selectedPage] item.setBrush(item.brush) ############################ # Resize Event # ############################ def resizeEvent(self, sizEvent): y = sizEvent.size().height() disline = (y / self.pageh) #Start if self.start == True: if self.height() < self.heditor.mainWindow.height(): if disline > self.displayLines: self.displayLines = (y / self.pageh) #Lines self.lines = self.filesize / (self.heditor.pagesPerBlock * self.heditor.pageSize) #Init self.initOffsetItems() self.initPageItems() #Refresh self.refreshOffsetItems(0) self.refreshPageItems(0) if self.lines > self.displayLines: self.wpage.setScrollBar() else: self.wpage.scroll = False self.start = False else: range = disline - self.displayLines if range > 0: self.displayLines = (y / self.pageh) #Append self.appendOffsetItems(range) self.appendPageItems(range) #Refresh self.refreshOffsetItems(self.heditor.startBlockOffset) self.refreshPageItems(self.heditor.startBlockOffset) # self.heditor.footer.pixel.view.resizeEvent(sizEvent) ############################ # CallBacks # ############################ def wheelEvent(self, event): offset = self.heditor.startBlockOffset # up = False if self.wpage.scroll: if event.delta() > 0: #UP subOffset = 3 * self.heditor.pagesPerBlock * self.heditor.pageSize if offset - subOffset > 0: offset = offset - subOffset else: offset = 0 else: #DOWN addOffset = 3 * self.heditor.pagesPerBlock * self.heditor.pageSize if offset + addOffset < self.filesize: offset = offset + addOffset else: offset = self.filesize - (5 * self.heditor.pagesPerBlock * self.heditor.pageSize) #Set ScrollBar value: if offset < self.filesize - (5 * self.heditor.pagesPerBlock * self.heditor.pageSize): value = self.wpage.scroll.offsetToValue(offset) self.wpage.scroll.setValue(value) self.refreshOffsetItems(offset) self.refreshPageItems(offset) def keyPressEvent(self, keyEvent): pass #if keyEvent.matches(QKeySequence.MoveToNextPage): #print "Next block" #elif keyEvent.matches(QKeySequence.MoveToPreviousPage): #print "Previous block" #elif keyEvent.matches(QKeySequence.MoveToNextLine): #print "Next Line" #elif keyEvent.matches(QKeySequence.MoveToPreviousLine): #print "Previous Line" #else: #pass def resetSelection(self): for item in self.pageItems: item.setBrush(item.brush) def getPageID(self, x, y): startx = 95 starty = 25 #Set scrollbar seek hscroll = self.horizontalScrollBar() if hscroll.value() > 0: startx -= hscroll.value() xrange = x - startx if xrange > 0: xcut = (xrange / (self.pagew + 2)) # print xcut else: xcut = 0 yrange = y - starty if yrange > 0: ycut = yrange / (self.pageh + 2) else: ycut = 0 id = (ycut * self.heditor.pagesPerBlock) + xcut return id def mousePressEvent(self, event): button = event.button() pos = event.pos() if event.button() == 1: #Get CLicked coordonates x = pos.x() y = pos.y() id = self.getPageID(x, y) self.resetSelection() self.heditor.pageselection.select(id, self.heditor.startBlockOffset, 0) def mouseMoveEvent(self, event): pos = event.pos() x = pos.x() y = pos.y() if self.heditor.pageselection.mode == 1: id = self.getPageID(x, y) self.resetSelection() self.heditor.pageselection.select(id, self.heditor.startBlockOffset, 1) # else: # id = self.getPageID(x, y) # self.pageItems[id].setBrush(self) def mouseReleaseEvent(self, event): self.heditor.pageselection.mode = 0