def image_meta(self, filescanner, patterns=('*', )): def fnmatch_any(fname, patterns): return any( fnmatch.fnmatch( fname.lower() if self.case_insensitive else fname, pattern) for pattern in patterns) imgmeta = [] batch = [] for path in filescanner: if fnmatch_any(path, patterns): imeta = image_meta_data(path) imgmeta.append(imeta) batch.append(imgmeta) if self.cancelled: return # raise UserInterruptError if len(batch) == 10 and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) batch = [] if batch and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) return imgmeta
def run(self): imgmeta = [] filescanner = scan(self.startdir) patterns = ["*.{}".format(fmt.lower()) for fmt in self.formats] def fnmatch_any(fname, patterns): return any(fnmatch.fnmatch(fname.lower(), pattern) for pattern in patterns) batch = [] for path in filescanner: if fnmatch_any(path, patterns): imeta = image_meta_data(path) imgmeta.append(imeta) batch.append(imgmeta) if self.cancelled: return # raise UserInterruptError if len(batch) == 10 and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) batch = [] if batch and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) return imgmeta
def image_meta(self, filescanner, patterns=('*', )): def fnmatch_any(fname, patterns): return any(fnmatch.fnmatch(fname.lower() if self.case_insensitive else fname, pattern) for pattern in patterns) imgmeta = [] batch = [] for path in filescanner: if fnmatch_any(path, patterns): imeta = image_meta_data(path) imgmeta.append(imeta) batch.append(imgmeta) if self.cancelled: return # raise UserInterruptError if len(batch) == 10 and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) batch = [] if batch and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) return imgmeta
def test_line_to_edge(self): """Show lint_to_edge() works as expected.""" self.challenge.lines = ['one', '1->2:12'] self.assertEqual(namespace(head=2, tail=1, weight=12), self.challenge.line_to_edge(1)) self.challenge.lines = ['one', '1->2'] self.assertEqual(namespace(head=2, tail=1), self.challenge.line_to_edge(1))
def _setup_plot(self): """Setup the plot with new curve data.""" assert self.data is not None self.graph.reset() data, domain = self.data, self.data.domain self.graph.getAxis('bottom').setTicks([[ (i + 1, str(a)) for i, a in enumerate(self.graph_variables) ]]) X = np.arange(1, len(self.graph_variables) + 1) groups = [] if not self.selected_classes: group_data = data[:, self.graph_variables] items, mean, meancurve, errorbar = self._plot_curve( X, QColor(Qt.darkGray), group_data, list(range(len(self.data)))) groups.append( namespace(data=group_data, profiles=items, mean=meancurve, boxplot=errorbar)) else: var = domain[self.group_var] class_col_data, _ = data.get_column_view(var) group_indices = [ np.flatnonzero(class_col_data == i) for i in range(len(self.classes)) ] for i, indices in enumerate(group_indices): if len(indices) == 0: groups.append(None) else: if self.classes: color = self.class_colors[i] else: color = QColor(Qt.darkGray) group_data = data[indices, self.graph_variables] items, mean, meancurve, errorbar = self._plot_curve( X, color, group_data, indices) groups.append( namespace(data=group_data, indices=indices, profiles=items, mean=meancurve, boxplot=errorbar)) self.__groups = groups self.__update_visibility()
def preprocess(self, frame): image_height, image_width = frame.shape[:2] scale = min(self.h / image_height, self.w / image_width) processed_image = cv2.resize(frame, None, fx=scale, fy=scale) processed_image = processed_image.astype('float32').transpose(2, 0, 1) return namespace( original_image=frame, meta=namespace( original_size=frame.shape[:2], processed_size=processed_image.shape[1:3], ), im_data=processed_image, im_info=np.array([processed_image.shape[1], processed_image.shape[2], 1.0], dtype='float32'), )
def _read_text_data(self): text_data = [] errors = [] patterns = ["*.{}".format(fmt.lower()) for fmt in self.formats] scan = self.scan_url if self._is_url else self.scan paths = scan(self.startdir, include_patterns=patterns) n_paths = len(paths) batch = [] if n_paths == 0: raise NoDocumentsException() for path in paths: if len(batch) == 1 and self._report_progress is not None: self._report_progress( namespace(progress=len(text_data) / n_paths, lastpath=path, batch=batch)) batch = [] reader = Reader.get_reader(path) if not self._is_url \ else UrlReader(path) text, error = reader.read() if text is not None: text_data.append(text) batch.append(text_data) else: errors.append(error) if self.cancelled: return return text_data, errors
def run(self): text_data = [] errors = [] patterns = ["*.{}".format(fmt.lower()) for fmt in self.formats] paths = self.scan(self.startdir, include_patterns=patterns) n_paths = len(paths) batch = [] for path in paths: if len(batch) == 1 and self._report_progress is not None: self._report_progress( namespace(progress=len(text_data) / n_paths, lastpath=path, batch=batch)) batch = [] reader = Reader.get_reader(path) text, error = reader.read() if text is not None: text_data.append(text) batch.append(text_data) else: errors.append(error) if self.cancelled: return self._text_data = text_data return self._create_corpus(), errors
def info(file_path): if file_path in allinforemote: info = allinforemote[file_path] else: info = allinfolocal[file_path] islocal = file_path in allinfolocal isremote = file_path in allinforemote outdated = islocal and isremote and ( allinforemote[file_path].get('version', '') != allinfolocal[file_path].get('version', '')) islocal &= not outdated prefix = os.path.join('', *file_path[:-1]) filename = file_path[-1] return namespace( prefix=prefix, filename=filename, title=info.get("title", filename), datetime=info.get("datetime", None), description=info.get("description", None), references=info.get("references", []), seealso=info.get("seealso", []), source=info.get("source", None), year=info.get("year", None), instances=info.get("instances", None), variables=info.get("variables", None), target=info.get("target", None), missing=info.get("missing", None), tags=info.get("tags", []), size=info.get("size", None), islocal=islocal, outdated=outdated )
def __init__(self, tfds_ds_name: str) -> None: self._adapter = _TFDS_ADAPTERS[tfds_ds_name] tfds_builder = tfds.builder(tfds_ds_name) tfds_ds_info = tfds_builder.info self._categories = {} self._state = namespace() self._adapter.transform_categories(tfds_builder, self._categories, self._state) tfds_decoders = {} for tfds_feature_name, tfds_fc in tfds_ds_info.features.items(): if isinstance(tfds_fc, tfds.features.Image): tfds_decoders[tfds_feature_name] = tfds.decode.SkipDecoding() tfds_builder.download_and_prepare() self._tfds_ds = tfds_builder.as_dataset(decoders=tfds_decoders) self._split_extractors = { split_name: _TfdsSplitExtractor(self, split, tfds_ds_info.splits[split_name]) # Since dicts in Python 3.7+ (and de facto in 3.6+) are # order-preserving, sort the splits by name so that we always # iterate over them in alphabetical order. for split_name, split in sorted(self._tfds_ds.items()) }
def __init__(self, obj): # type: (Q) -> None assert isinstance(obj, QObject) self.__obj = obj def finalize(_weakref): # finalize when self is collected if state.objref is None: return objref = state.objref() if objref is not None: objref.destroyed.disconnect(state.zero_ref) # destroy/zero the reference when QObject is destroyed def zero_ref(): selfref = state.selfref() if selfref is not None: selfref.__obj = None state.objref = None state = namespace(selfref=weakref.ref(self, finalize), objref=weakref.ref(obj), zero_ref=zero_ref, finalize=finalize) self.__state = state # Must not capture self in the zero_ref's closure obj.destroyed.connect(zero_ref, Qt.DirectConnection)
def commit(self): if self._task is not None: self.cancel() if not self._image_attributes or self._input_data is None: self.clear_outputs() return embedder = self.connect() _executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) self.cancel_button.setDisabled(False) self.cb_image_attr.setDisabled(True) self.cb_embedder.setDisabled(True) file_paths_attr = self._image_attributes[self.cb_image_attr_current_id] file_paths = self._input_data[:, file_paths_attr].metas.flatten() file_paths_mask = file_paths == file_paths_attr.Unknown file_paths_valid = file_paths[~file_paths_mask] ticks = iter(np.linspace(0.0, 100.0, file_paths_valid.size)) set_progress = qconcurrent.methodinvoke( self, "__progress_set", (float,)) def advance(success=True): if success: set_progress(next(ticks)) def cancel(): task.future.cancel() task.cancelled = True task.embedder.set_canceled(True) def run_embedding(): return embedder( self._input_data, col=file_paths_attr, image_processed_callback=advance) self.auto_commit_widget.setDisabled(True) self.progressBarInit() self.progressBarSet(0.0) self.setBlocking(True) f = _executor.submit(run_embedding) f.add_done_callback( qconcurrent.methodinvoke(self, "__set_results", (object,))) task = self._task = namespace( file_paths_mask=file_paths_mask, file_paths_valid=file_paths_valid, file_paths=file_paths, embedder=embedder, cancelled=False, cancel=cancel, future=f, ) self._log.debug("Starting embedding task for %i images", file_paths.size) return
def commit(self, force=False): self.Error.clear() # Kill any running jobs self.cancel() assert self.__state == self.State.Pending if self.data is None: return # We commit if auto_commit is on or when we force commit if not self.auto_commit and not force: return # Make sure the dataset is ok if np.any(np.isnan(self.data.X)): self.Error.data_has_nans() return if len(self.data.domain.attributes) < 1: self.Error.empty_dataset() return # Prepare the tasks to run queue = TaskQueue(parent=self) if self.pca_projection is None and self.apply_pca: queue.push(namespace(task=self._compute_pca_projection)) if self.graph is None: queue.push( namespace(task=self._compute_graph, progress_callback=True)) if self.partition is None: queue.push(namespace(task=self._compute_partition)) # Prepare callbacks queue.on_progress.connect(lambda val: self.progressBarSet(100 * val)) queue.on_complete.connect(self._processing_complete) queue.on_complete.connect(self._send_data) queue.on_exception.connect(self._handle_exceptions) # Run the task queue self.progressBarInit() self.setBlocking(True) self.__future = self.__executor.submit(queue.start) self.__state = self.State.Running
def _new_plotdata(self): self.plotdata = namespace(valid_mask=None, embedding_coords=None, axisitems=[], axes=[], variables=[], data=None, hidecircle=None)
def _new_plotdata(self): self.plotdata = namespace( valid_mask=None, embedding_coords=None, axisitems=[], axes=[], variables=[], data=None, hidecircle=None )
def _new_plotdata(self): self.plotdata = namespace( valid_mask=None, embedding_coords=None, points=None, arcarrows=[], point_labels=[], rand=None, data=None, )
def commit(self): self.Error.clear() # Kill any running jobs self.cancel() if self.data is None: return # Make sure the dataset is ok if len(self.data.domain.attributes) < 1: self.Error.empty_dataset() return # Preprocess the dataset if self.preprocessed_data is None: louvain = Louvain() self.preprocessed_data = louvain.preprocess(self.data) # Prepare the tasks to run queue = TaskQueue(parent=self) if self.pca_projection is None and self.apply_pca: queue.push(namespace(task=self._compute_pca_projection)) if self.graph is None: queue.push( namespace(task=self._compute_graph, progress_callback=True)) if self.partition is None: queue.push(namespace(task=self._compute_partition)) # Prepare callbacks queue.on_progress.connect(lambda val: self.progressBarSet(100 * val)) queue.on_complete.connect(self._on_complete) queue.on_exception.connect(self._handle_exceptions) self.__queue = queue # Run the task queue self.progressBarInit() self.setBlocking(True) self.__future = self.__executor.submit(queue.start)
def __init__(self, pair1, pair2, log_level='DEBUG', *args, **kwargs): self.files = namespace() self.files.raw_pair = Fastq(pair1), Fastq(pair2) self.run = self.files.raw_pair[0].dir.dirname self.name = self.files.raw_pair[0].sample_name self.taxon = 'UNKNOWN' self._logger = self.configure_logging(level=log_level) self.log("Creating Isolate Instance", lvl="INFO") self.build_filesystem()
def setScores(self, scores, labels, values, colors, rownames=None): """ Set the silhouette scores/labels to for display. Arguments --------- scores : (N,) ndarray The silhouette scores. labels : (N,) ndarray A ndarray (dtype=int) of label/clusters indices. values : list of str A list of label/cluster names. colors : (N, 3) ndarray A ndarray of RGB values. rownames : list of str, optional A list (len == N) of row names. """ scores = np.asarray(scores, dtype=float) labels = np.asarray(labels, dtype=int) if rownames is not None: rownames = np.asarray(rownames, dtype=object) if not scores.ndim == labels.ndim == 1: raise ValueError("scores and labels must be 1 dimensional") if scores.shape != labels.shape: raise ValueError("scores and labels must have the same shape") if rownames is not None and rownames.shape != scores.shape: raise ValueError("rownames must have the same size as scores") Ck = np.unique(labels) if not Ck[0] >= 0 and Ck[-1] < len(values): raise ValueError( "All indices in `labels` must be in `range(len(values))`") cluster_indices = [ np.flatnonzero(labels == i) for i in range(len(values)) ] cluster_indices = [ indices[np.argsort(scores[indices])[::-1]] for indices in cluster_indices ] groups = [ namespace( scores=scores[indices], indices=indices, label=label, rownames=(rownames[indices] if rownames is not None else None), color=color) for indices, label, color in zip(cluster_indices, values, colors) ] self.clear() self.__groups = groups self.__setup()
def _preprocess(self, frame): image_height, image_width = frame.shape[:2] scale = min(self.h / image_height, self.w / image_width) processed_image = cv2.resize(frame, None, fx=scale, fy=scale) processed_image = processed_image.astype('float32').transpose(2, 0, 1) height, width = processed_image.shape[1], processed_image.shape[2] im_info = np.array([height, width, 1.0], dtype='float32') if self.segmentoly_type else None meta = namespace( original_size=frame.shape[:2], processed_size=processed_image.shape[1:3], ) return processed_image, im_info, meta
def __plot_group(self, X, data, index=None): p = QPen(self.__get_line_color(None, index), LinePlotStyle.MEAN_WIDTH) p.setCosmetic(True) mean = np.nanmean(data.X, axis=0) mean_curve = self.get_mean_curve(X, mean, p) range_curve = self.get_range_curve(X, data, p) error_bar = self.get_error_bar(X, data, mean) self.graph.addItem(mean_curve) self.graph.addItem(range_curve) self.graph.addItem(error_bar) self.__groups.append(namespace(mean=mean_curve, range=range_curve, error_bar=error_bar))
def parse_header(data, pos=0): (magic,), pos = parse_format('<i', data, pos) if magic != 0x7eb2fdd6: raise ValueError("Bad OpenFst TRIE: wrong magic number") (fst_type,), pos = parse_string(data, pos) (arc_type,), pos = parse_string(data, pos) (version, flags, properties, start_state, num_states, num_arcs), pos = parse_format('<iiQqqq', data, pos) if fst_type != b'const' or arc_type != b'standard' or version != 1: raise ValueError("Cannot parse OpenFst TRIE: this version of format is not supported") return namespace( magic=magic, fst_type=fst_type, arc_type=arc_type, version=version, flags=flags, properties=properties, start_state=start_state, num_states=num_states, num_arcs=num_arcs, ), pos
def __plot_mean_with_error(self, X, data, index=None): pen = QPen(self.__get_line_color(None, index), 4) pen.setCosmetic(True) mean = np.nanmean(data.X, axis=0) mean_curve = pg.PlotDataItem(x=X, y=mean, pen=pen, symbol="o", symbolSize=5, antialias=True) self.graph.addItem(mean_curve) q1, q2, q3 = np.nanpercentile(data.X, [25, 50, 75], axis=0) bottom = np.clip(mean - q1, 0, mean - q1) top = np.clip(q3 - mean, 0, q3 - mean) error_bar = pg.ErrorBarItem(x=X, y=mean, bottom=bottom, top=top, beam=0.01) self.graph.addItem(error_bar) self.__groups.append(namespace(mean=mean_curve, error_bar=error_bar))
def run(self): imgmeta = [] filescanner = scan(self.startdir) patterns = ["*.{}".format(fmt.lower()) for fmt in self.formats] def fnmatch_any(fname, patterns): return any( fnmatch.fnmatch(fname.lower(), pattern) for pattern in patterns) batch = [] for path in filescanner: if fnmatch_any(path, patterns): imeta = image_meta_data(path) imgmeta.append(imeta) batch.append(imgmeta) if self.cancelled: return # raise UserInterruptError if len(batch) == 10 and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) batch = [] if batch and self.report_progress is not None: self.report_progress( namespace(count=len(imgmeta), lastpath=imgmeta[-1].path, batch=batch)) return imgmeta
def _new_plotdata(self): self.plotdata = namespace( validmask=None, embedding_coords=None, anchors=[], anchoritem=[], X=None, Y=None, indicators=[], hidecircle=None, data=None, items=[], topattrs=None, rand=None, selection=None, # np.array )
def setScores(self, scores, labels, values, colors, rownames=None): """ Set the silhouette scores/labels to for display. Arguments --------- scores : (N,) ndarray The silhouette scores. labels : (N,) ndarray A ndarray (dtype=int) of label/clusters indices. values : list of str A list of label/cluster names. colors : (N, 3) ndarray A ndarray of RGB values. rownames : list of str, optional A list (len == N) of row names. """ scores = np.asarray(scores, dtype=float) labels = np.asarray(labels, dtype=int) if rownames is not None: rownames = np.asarray(rownames, dtype=object) if not scores.ndim == labels.ndim == 1: raise ValueError("scores and labels must be 1 dimensional") if scores.shape != labels.shape: raise ValueError("scores and labels must have the same shape") if rownames is not None and rownames.shape != scores.shape: raise ValueError("rownames must have the same size as scores") Ck = np.unique(labels) if not Ck[0] >= 0 and Ck[-1] < len(values): raise ValueError( "All indices in `labels` must be in `range(len(values))`") cluster_indices = [np.flatnonzero(labels == i) for i in range(len(values))] cluster_indices = [indices[np.argsort(scores[indices])[::-1]] for indices in cluster_indices] groups = [ namespace(scores=scores[indices], indices=indices, label=label, rownames=(rownames[indices] if rownames is not None else None), color=color) for indices, label, color in zip(cluster_indices, values, colors) ] self.clear() self.__groups = groups self.__setup()
def parse_openfst(data, pos=0, base_offset=0): header, pos = parse_header(data, pos) pos = align_pos(pos, align=16, base_offset=base_offset) states = [] for state_idx in range(header.num_states): # pylint: disable=unused-variable state, pos = parse_state(data, pos) states.append(state) pos = align_pos(pos, align=16, base_offset=base_offset) arcs = [] for arc_idx in range(header.num_arcs): # pylint: disable=unused-variable arc, pos = parse_arc(data, pos) arcs.append(arc) fst = namespace(meta=header, states=states, arcs=arcs) return fst, pos
def mock_service(): s = namespace( list=namespace( organism=namespace(get=lambda: list_organism), pathway=lambda org: {"hsa": namespace(get=lambda: list_pathway_hsa)}[org], ), info=lambda db: {"pathway": namespace(get=lambda: info_pathway)}[db], get=lambda key: {"genome:T01001": namespace(get=lambda: genome_T01001)}[key], ) return s
def read_py_config(filename): filename = osp.abspath(osp.expanduser(filename)) check_file_exist(filename) assert filename.endswith('.py') module_name = osp.basename(filename)[:-3] if '.' in module_name: raise ValueError('Dots are not allowed in config file path.') config_dir = osp.dirname(filename) sys.path.insert(0, config_dir) mod = import_module(module_name) sys.path.pop(0) return namespace( **{ name: value for name, value in mod.__dict__.items() if not name.startswith('__') })
def preprocess_inputs(self): _, _, height, width = self.encoder.input("imgs").shape target_shape = (height, width) if os.path.isdir(self.args.input): inputs = sorted( os.path.join(self.args.input, inp) for inp in os.listdir(self.args.input)) else: inputs = [self.args.input] for filenm in tqdm(inputs): image_raw = cv.imread(filenm) assert image_raw is not None, "Error reading image {}".format( filenm) image = preprocess_image( PREPROCESSING[self.args.preprocessing_type], image_raw, target_shape) record = namespace(img_name=filenm, img=image) self.images_list.append(record)
def mousePressEvent(self, event): # Reimplemented if event.button() == Qt.LeftButton: if event.modifiers() & Qt.ControlModifier: saction = SelectAction.Toogle elif event.modifiers() & Qt.AltModifier: saction = SelectAction.Deselect elif event.modifiers() & Qt.ShiftModifier: saction = SelectAction.Select else: saction = SelectAction.Clear | SelectAction.Select self.__selstate = namespace( modifiers=event.modifiers(), selection=self.__selection, action=saction, rect=None ) if saction & SelectAction.Clear: self.__selstate.selection = numpy.array([], dtype=int) self.setSelection(self.__selstate.selection) event.accept()
def test_lines_to_edges(self): """Show lines_to_edges() works as expected.""" self.challenge.lines = ['1->2', '2->3', '3->4'] expect = [ namespace(head=2, tail=1), namespace(head=3, tail=2), namespace(head=4, tail=3) ] self.assertEqual(expect, self.challenge.lines_to_edges()) expect = [namespace(head=3, tail=2)] self.assertEqual(expect, self.challenge.lines_to_edges(1, 2)) self.challenge.lines = ['1->2:22'] expect = [namespace(head=2, tail=1, weight=22)] self.assertEqual(expect, self.challenge.lines_to_edges()) self.challenge.lines = ['1->2, 3', '2->3'] expect = [ namespace(head='2', tail=1), namespace(head='3', tail=1), namespace(head=3, tail=2) ] self.assertEqual(expect, self.challenge.lines_to_edges())
def info(prefix, filename): if (prefix, filename) in allinforemote: info = allinforemote[prefix, filename] else: info = allinfolocal[prefix, filename] islocal = (prefix, filename) in allinfolocal return namespace(prefix=prefix, filename=filename, title=info.get("title", filename), datetime=info.get("datetime", None), description=info.get("description", None), reference=info.get("reference", None), instances=info.get("instances", None), variables=info.get("variables", None), target=info.get("target", None), missing=info.get("missing", None), tags=info.get("tags", []), size=info.get("size", None), islocal=islocal)
def mock_service(): s = namespace( list=namespace( organism=namespace(get=lambda: list_organism), pathway=lambda org: { "hsa": namespace(get=lambda: list_pathway_hsa) }[org], ), info=lambda db: {"pathway": namespace(get=lambda: info_pathway)}[db], get=lambda key: { "genome:T01001": namespace(get=lambda: genome_T01001) }[key], ) return s
def mousePressEvent(self, event): # Reimplemented if event.button() == Qt.LeftButton: if event.modifiers() & Qt.ControlModifier: saction = SelectAction.Toogle elif event.modifiers() & Qt.AltModifier: saction = SelectAction.Deselect elif event.modifiers() & Qt.ShiftModifier: saction = SelectAction.Select else: saction = SelectAction.Clear | SelectAction.Select self.__selstate = namespace( modifiers=event.modifiers(), selection=self.__selection, action=saction, rect=None, ) if saction & SelectAction.Clear: self.__selstate.selection = np.array([], dtype=int) self.setSelection(self.__selstate.selection) event.accept()
def get_pairs( cls, path=os.getcwd(), r1="_R1_", r2="_R2_", ): """Return list of Fastq objects of paired-end reads in directory: `path`""" if isinstance(path, Dir): directory = path elif isinstance(path, str): directory = Dir(path) else: raise TypeError( f"path must be of type str or Dir. NOT: {type(path)}") read1 = [ Fastq(file.path) for file in directory.files(endswith=cls.extensions, contains=r1) ] return [ namespace(pair1=pair1, pair2=Fastq(pair1.path.replace(r1, r2))) for pair1 in read1 if os.path.exists(pair1.path.replace(r1, r2)) ]
def _setup(self): """ Setup the plot. """ X = self.data.X Y = self.data.Y mask = numpy.bitwise_or.reduce(numpy.isnan(X), axis=1) mask |= numpy.isnan(Y) valid = ~mask X = X[valid, :] Y = Y[valid] if self.data.domain.class_var.is_discrete: Y = Y.astype(int) X = (X - numpy.mean(X, axis=0)) span = numpy.ptp(X, axis=0) X[:, span > 0] /= span[span > 0].reshape(1, -1) if self.initialization == OWFreeViz.Circular: anchors = linproj.linproj.defaultaxes(X.shape[1]).T else: anchors = numpy.random.random((X.shape[1], 2)) * 2 - 1 EX = numpy.dot(X, anchors) radius = numpy.max(numpy.linalg.norm(EX, axis=1)) jittervec = numpy.random.RandomState(4).rand(*EX.shape) * 2 - 1 jittervec *= 0.01 _, jitterfactor = self.JitterAmount[self.jitter] colorvar = self._color_var() shapevar = self._shape_var() sizevar = self._size_var() labelvar = self._label_var() if colorvar is not None: colors = plotutils.color_data(self.data, colorvar)[valid] else: colors = numpy.array([[192, 192, 192]]) colors = numpy.tile(colors, (X.shape[0], 1)) pendata = plotutils.pen_data(colors * 0.8) colors = numpy.hstack( [colors, numpy.full((colors.shape[0], 1), float(self.opacity))]) brushdata = plotutils.brush_data(colors) shapedata = plotutils.shape_data(self.data, shapevar)[valid] sizedata = size_data( self.data, sizevar, pointsize=self.point_size)[valid] if labelvar is not None: labeldata = plotutils.column_data(self.data, labelvar, valid) labeldata = [labelvar.str_val(val) for val in labeldata] else: labeldata = None coords = (EX / radius) + jittervec * jitterfactor item = linproj.ScatterPlotItem( x=coords[:, 0], y=coords[:, 1], brush=brushdata, pen=pendata, symbols=shapedata, size=sizedata, data=numpy.flatnonzero(valid), antialias=True, ) self.plot.addItem(item) self.plot.setRange(QtCore.QRectF(-1.05, -1.05, 2.1, 2.1)) # minimum visible anchor radius minradius = self.min_anchor_radius / 100 + 1e-5 axisitems = [] for anchor, var in zip(anchors, self.data.domain.attributes): axitem = AxisItem( line=QtCore.QLineF(0, 0, *anchor), label=var.name,) axitem.setVisible(numpy.linalg.norm(anchor) > minradius) axitem.setPen(pg.mkPen((100, 100, 100))) axitem.setArrowVisible(False) self.plot.addItem(axitem) axisitems.append(axitem) hidecircle = QtGui.QGraphicsEllipseItem() hidecircle.setRect( QtCore.QRectF(-minradius, -minradius, 2 * minradius, 2 * minradius)) _pen = QtGui.QPen(Qt.lightGray, 1) _pen.setCosmetic(True) hidecircle.setPen(_pen) self.plot.addItem(hidecircle) self.plotdata = namespace( validmask=valid, embedding_coords=EX, jittervec=jittervec, anchors=anchors, mainitem=item, axisitems=axisitems, hidecircle=hidecircle, basecolors=colors, brushdata=brushdata, pendata=pendata, shapedata=shapedata, sizedata=sizedata, labeldata=labeldata, labelitems=[], densityimage=None, X=X, Y=Y, selectionmask=numpy.zeros_like(valid, dtype=bool) ) self._update_legend() self._update_labels() self._update_density()
def updated(self, **kwargs): ns = self.__dict__.copy() ns.update(**kwargs) return namespace(**ns)
def commit(self): if self._task is not None: self.cancel() if self._image_embedder is None: self._set_server_info(connected=False) return if not self._image_attributes or self._input_data is None: self.Outputs.embeddings.send(None) self.Outputs.skipped_images.send(None) return self._set_server_info(connected=True) self.cancel_button.setDisabled(False) self.cb_image_attr.setDisabled(True) self.cb_embedder.setDisabled(True) file_paths_attr = self._image_attributes[self.cb_image_attr_current_id] file_paths = self._input_data[:, file_paths_attr].metas.flatten() origin = file_paths_attr.attributes.get("origin", "") if urlparse(origin).scheme in ("http", "https", "ftp", "data") and \ origin[-1] != "/": origin += "/" assert file_paths_attr.is_string assert file_paths.dtype == np.dtype('O') file_paths_mask = file_paths == file_paths_attr.Unknown file_paths_valid = file_paths[~file_paths_mask] for i, a in enumerate(file_paths_valid): urlparts = urlparse(a) if urlparts.scheme not in ("http", "https", "ftp", "data"): if urlparse(origin).scheme in ("http", "https", "ftp", "data"): file_paths_valid[i] = urljoin(origin, a) else: file_paths_valid[i] = os.path.join(origin, a) ticks = iter(np.linspace(0.0, 100.0, file_paths_valid.size)) set_progress = qconcurrent.methodinvoke( self, "__progress_set", (float,)) def advance(success=True): if success: set_progress(next(ticks)) def cancel(): task.future.cancel() task.cancelled = True task.embedder.set_canceled(True) embedder = self._image_embedder def run_embedding(paths): return embedder( file_paths=paths, image_processed_callback=advance) self.auto_commit_widget.setDisabled(True) self.progressBarInit(processEvents=None) self.progressBarSet(0.0, processEvents=None) self.setBlocking(True) f = self._executor.submit(run_embedding, file_paths_valid) f.add_done_callback( qconcurrent.methodinvoke(self, "__set_results", (object,))) task = self._task = namespace( file_paths_mask=file_paths_mask, file_paths_valid=file_paths_valid, file_paths=file_paths, embedder=embedder, cancelled=False, cancel=cancel, future=f, ) self._log.debug("Starting embedding task for %i images", file_paths.size) return
#!/usr/bin/env python3 ''' keysym module; ''' from types import SimpleNamespace as namespace import curses ## keyname to keycode mapping; ## ## keynames are used in config files; keyname = namespace() keyname.space = ord(' ') keyname.enter = ord('\n') keyname.left = curses.KEY_LEFT keyname.right = curses.KEY_RIGHT keyname.down = curses.KEY_DOWN keyname.up = curses.KEY_UP keyname.f1 = curses.KEY_F1 keyname.f2 = curses.KEY_F2 keyname.f3 = curses.KEY_F3 keyname.f4 = curses.KEY_F4 keyname.f5 = curses.KEY_F5 keyname.f6 = curses.KEY_F6 keyname.f7 = curses.KEY_F7 keyname.f8 = curses.KEY_F8 ## keysym to keycode mapping; ##
#!/usr/bin/env python3 ''' config module; ''' from os.path import expanduser from types import SimpleNamespace as namespace import yaml from ncmpy.keysym import keysym as ks from ncmpy.keysym import name2code as n2c ## config; conf = namespace() ## default config values; conf.mpd_host = 'localhost' conf.mpd_port = 6600 conf.rate_song = True conf.lyrics_dir = expanduser('~/.ncmpy/lyrics') ## read config files; for fname in [ expanduser('~/.config/ncmpy/ncmpy.yaml'), '/etc/ncmpy/ncmpy.yaml', ]: try: with open(fname, 'rt') as fp: data = yaml.load(fp) except:
def _setup_plot(self): """Setup the plot with new curve data.""" assert self.data is not None data, domain = self.data, self.data.domain if is_discrete(domain.class_var): class_col_data, _ = data.get_column_view(domain.class_var) group_indices = [np.flatnonzero(class_col_data == i) for i in range(len(domain.class_var.values))] else: group_indices = [np.arange(len(data))] X = np.arange(1, len(domain.attributes)+1) groups = [] for i, indices in enumerate(group_indices): if self.classes: color = self.class_colors[i] else: color = QColor(Qt.darkGray) group_data = data[indices, :] plot_x, plot_y, connect = disconnected_curve_data(group_data.X, x=X) color.setAlpha(200) lightcolor = QColor(color.lighter(factor=150)) lightcolor.setAlpha(150) pen = QPen(color, 2) pen.setCosmetic(True) lightpen = QPen(lightcolor, 1) lightpen.setCosmetic(True) hoverpen = QPen(pen) hoverpen.setWidth(2) curve = pg.PlotCurveItem( x=plot_x, y=plot_y, connect=connect, pen=lightpen, symbolSize=2, antialias=True, ) self.graph.addItem(curve) hovercurves = [] for index, profile in zip(indices, group_data.X): hcurve = HoverCurve(x=X, y=profile, pen=hoverpen, antialias=True) hcurve.setToolTip('{}'.format(index)) hcurve._data_index = index hovercurves.append(hcurve) self.graph.addItem(hcurve) mean = np.nanmean(group_data.X, axis=0) meancurve = pg.PlotDataItem( x=X, y=mean, pen=pen, size=5, symbol="o", pxMode=True, symbolSize=5, antialias=True ) hoverpen = QPen(hoverpen) hoverpen.setWidth(5) hc = HoverCurve(x=X, y=mean, pen=hoverpen, antialias=True) hc.setFlag(QGraphicsItem.ItemIsSelectable, False) self.graph.addItem(hc) self.graph.addItem(meancurve) self.legend_items.append(meancurve) q1, q2, q3 = np.nanpercentile(group_data.X, [25, 50, 75], axis=0) # TODO: implement and use a box plot item errorbar = pg.ErrorBarItem( x=X, y=mean, bottom=np.clip(mean - q1, 0, mean - q1), top=np.clip(q3 - mean, 0, q3 - mean), beam=0.5 ) self.graph.addItem(errorbar) groups.append( namespace( data=group_data, indices=indices, profiles=curve, hovercurves=hovercurves, mean=meancurve, boxplot=errorbar) ) self.__groups = groups self.__update_visibility() self.__update_tooltips()
def __init__(self): super().__init__() #: widget's runtime state self.__state = State.NoState self._imageMeta = [] self._imageCategories = {} self.__invalidated = False self.__pendingTask = None vbox = gui.vBox(self.controlArea) hbox = gui.hBox(vbox) self.recent_cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, ) self.recent_cb.activated[int].connect(self.__onRecentActivated) icons = standard_icons(self) browseaction = QAction( "Open/Load Images", self, iconText="\N{HORIZONTAL ELLIPSIS}", icon=icons.dir_open_icon, toolTip="Select a directory from which to load the images" ) browseaction.triggered.connect(self.__runOpenDialog) reloadaction = QAction( "Reload", self, icon=icons.reload_icon, toolTip="Reload current image set" ) reloadaction.triggered.connect(self.reload) self.__actions = namespace( browse=browseaction, reload=reloadaction, ) browsebutton = QPushButton( browseaction.iconText(), icon=browseaction.icon(), toolTip=browseaction.toolTip(), clicked=browseaction.trigger ) reloadbutton = QPushButton( reloadaction.iconText(), icon=reloadaction.icon(), clicked=reloadaction.trigger, default=True, ) hbox.layout().addWidget(self.recent_cb) hbox.layout().addWidget(browsebutton) hbox.layout().addWidget(reloadbutton) self.addActions([browseaction, reloadaction]) reloadaction.changed.connect( lambda: reloadbutton.setEnabled(reloadaction.isEnabled()) ) box = gui.vBox(vbox, "Info") self.infostack = QStackedWidget() self.info_area = QLabel( text="No image set selected", wordWrap=True ) self.progress_widget = QProgressBar( minimum=0, maximum=0 ) self.cancel_button = QPushButton( "Cancel", icon=icons.cancel_icon, ) self.cancel_button.clicked.connect(self.cancel) w = QWidget() vlayout = QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) hlayout = QHBoxLayout() hlayout.setContentsMargins(0, 0, 0, 0) hlayout.addWidget(self.progress_widget) hlayout.addWidget(self.cancel_button) vlayout.addLayout(hlayout) self.pathlabel = TextLabel() self.pathlabel.setTextElideMode(Qt.ElideMiddle) self.pathlabel.setAttribute(Qt.WA_MacSmallSize) vlayout.addWidget(self.pathlabel) w.setLayout(vlayout) self.infostack.addWidget(self.info_area) self.infostack.addWidget(w) box.layout().addWidget(self.infostack) self.__initRecentItemsModel() self.__invalidated = True self.__executor = ThreadExecutor(self) QApplication.postEvent(self, QEvent(RuntimeEvent.Init))
def update_scores(self): """Compute the scores and update the histogram. """ self.__cancel_pending() self.clear_plot() self.scores = None self.nulldist = None self.error(0) grp, split_selection = self.selected_split() if not self.data or grp is None: return _, side, test_type, score_func = self.Scores[self.score_index] def compute_scores(X, group_indices): arrays = [X[ind] for ind in group_indices] return score_func(*arrays, axis=0) def permute_indices(group_indices, random_state=None): assert all(ind.dtype.kind == "i" for ind in group_indices) assert all(ind.ndim == 1 for ind in group_indices) if random_state is None: random_state = np.random joined = np.hstack(group_indices) random_state.shuffle(joined) split_ind = np.cumsum([len(ind) for ind in group_indices]) return np.split(joined, split_ind[:-1]) if isinstance(grp, grouputils.RowGroup): axis = 0 else: axis = 1 if test_type == OWFeatureSelection.TwoSampleTest: G1 = grouputils.group_selection_mask( self.data, grp, split_selection) G2 = ~G1 indices = [np.flatnonzero(G1), np.flatnonzero(G2)] elif test_type == self.VarSampleTest: indices = [grouputils.group_selection_mask(self.data, grp, [i]) for i in range(len(grp.values))] indices = [np.flatnonzero(ind) for ind in indices] else: assert False if not all(np.count_nonzero(ind) > 0 for ind in indices): self.error(0, "Target labels most exclude/include at least one " "value.") self.scores = None self.nulldist = None self.update_data_info_label() return X = self.data.X if axis == 1: X = X.T # TODO: Check that each label has more than one measurement, # raise warning otherwise. def compute_scores_with_perm(X, indices, nperm=0, rstate=None, progress_advance=None): scores = compute_scores(X, indices, ) if progress_advance is not None: progress_advance() null_scores = [] if nperm > 0: if rstate is None: rstate = np.random.RandomState(0) for i in range(nperm): p_indices = permute_indices(indices, rstate) assert all(pind.shape == ind.shape for pind, ind in zip(indices, p_indices)) pscore = compute_scores(X, p_indices) assert pscore.shape == scores.shape null_scores.append(pscore) if progress_advance is not None: progress_advance() return scores, null_scores p_advance = concurrent.methodinvoke( self, "progressBarAdvance", (float,)) state = namespace(cancelled=False, advance=p_advance) def progress(): if state.cancelled: raise concurrent.CancelledError else: state.advance(100 / (nperm + 1)) self.progressBarInit() set_scores = concurrent.methodinvoke( self, "__set_score_results", (concurrent.Future,)) nperm = self.permutations_count if self.compute_null else 0 self.__scores_state = state self.__scores_future = self._executor.submit( compute_scores_with_perm, X, indices, nperm, progress_advance=progress) self.__scores_future.add_done_callback(set_scores)
def start(self): """ Start/execute the image indexing operation """ self.error() self.__invalidated = False if self.currentPath is None: return if self.__state == State.Processing: assert self.__pendingTask is not None log.info("Starting a new task while one is in progress. " "Cancel the existing task (dir:'{}')" .format(self.__pendingTask.startdir)) self.cancel() startdir = self.currentPath self.__setRuntimeState(State.Processing) report_progress = methodinvoke( self, "__onReportProgress", (object,)) task = ImageScan(startdir, report_progress=report_progress) # collect the task state in one convenient place self.__pendingTask = taskstate = namespace( task=task, startdir=startdir, future=None, watcher=None, cancelled=False, cancel=None, ) def cancel(): # Cancel the task and disconnect if taskstate.future.cancel(): pass else: taskstate.task.cancelled = True taskstate.cancelled = True try: taskstate.future.result(timeout=3) except UserInterruptError: pass except TimeoutError: log.info("The task did not stop in in a timely manner") taskstate.watcher.finished.disconnect(self.__onRunFinished) taskstate.cancel = cancel def run_image_scan_task_interupt(): try: return task.run() except UserInterruptError: # Suppress interrupt errors, so they are not logged return taskstate.future = self.__executor.submit(run_image_scan_task_interupt) taskstate.watcher = FutureWatcher(taskstate.future) taskstate.watcher.finished.connect(self.__onRunFinished)
def _setup_plot(self): """Setup the plot with new curve data.""" assert self.data is not None self.graph.clear() data, domain = self.data, self.data.domain var = domain[self.group_var] class_col_data, _ = data.get_column_view(var) group_indices = [np.flatnonzero(class_col_data == i) for i in range(len(self.classes))] self.graph.getAxis('bottom').setTicks([ [(i+1, str(a)) for i, a in enumerate(self.graph_variables)] ]) X = np.arange(1, len(self.graph_variables)+1) groups = [] for i, indices in enumerate(group_indices): if len(indices) == 0: groups.append(None) else: if self.classes: color = self.class_colors[i] else: color = QColor(Qt.darkGray) group_data = data[indices, self.graph_variables] plot_x, plot_y, connect = disconnected_curve_data(group_data.X, x=X) color.setAlpha(200) lightcolor = QColor(color.lighter(factor=150)) lightcolor.setAlpha(150) pen = QPen(color, 2) pen.setCosmetic(True) lightpen = QPen(lightcolor, 1) lightpen.setCosmetic(True) curve = pg.PlotCurveItem( x=plot_x, y=plot_y, connect=connect, pen=lightpen, symbolSize=2, antialias=True, ) self.graph.addItem(curve) mean = np.nanmean(group_data.X, axis=0) meancurve = pg.PlotDataItem( x=X, y=mean, pen=pen, size=5, symbol="o", pxMode=True, symbolSize=5, antialias=True ) self.graph.addItem(meancurve) q1, q2, q3 = np.nanpercentile(group_data.X, [25, 50, 75], axis=0) # TODO: implement and use a box plot item errorbar = pg.ErrorBarItem( x=X, y=mean, bottom=np.clip(mean - q1, 0, mean - q1), top=np.clip(q3 - mean, 0, q3 - mean), beam=0.5 ) self.graph.addItem(errorbar) groups.append( namespace( data=group_data, indices=indices, profiles=curve, mean=meancurve, boxplot=errorbar) ) self.__groups = groups self.__update_visibility()
def __init__(self, parent=None): super().__init__(parent) self.data = None self.subset_data = None self._subset_mask = None self._selection_mask = None self._item = None self.__legend = None self.__selection_item = None self.__replot_requested = False box = gui.widgetBox(self.controlArea, "Axes") box1 = gui.widgetBox(box, "Displayed", margin=0) box1.setFlat(True) self.active_view = view = QListView( sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Ignored), selectionMode=QListView.ExtendedSelection, dragEnabled=True, defaultDropAction=Qt.MoveAction, dragDropOverwriteMode=False, dragDropMode=QListView.DragDrop, showDropIndicator=True, minimumHeight=50, ) view.viewport().setAcceptDrops(True) movedown = QAction( "Move down", view, shortcut=QKeySequence(Qt.AltModifier | Qt.Key_Down), triggered=self.__deactivate_selection ) view.addAction(movedown) self.varmodel_selected = model = DnDVariableListModel( parent=self) model.rowsInserted.connect(self._invalidate_plot) model.rowsRemoved.connect(self._invalidate_plot) model.rowsMoved.connect(self._invalidate_plot) view.setModel(model) box1.layout().addWidget(view) box1 = gui.widgetBox(box, "Other", margin=0) box1.setFlat(True) self.other_view = view = QListView( sizePolicy=QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Ignored), selectionMode=QListView.ExtendedSelection, dragEnabled=True, defaultDropAction=Qt.MoveAction, dragDropOverwriteMode=False, dragDropMode=QListView.DragDrop, showDropIndicator=True, minimumHeight=50 ) view.viewport().setAcceptDrops(True) moveup = QtGui.QAction( "Move up", view, shortcut=QKeySequence(Qt.AltModifier | Qt.Key_Up), triggered=self.__activate_selection ) view.addAction(moveup) self.varmodel_other = model = DnDVariableListModel(parent=self) view.setModel(model) box1.layout().addWidget(view) box = gui.widgetBox(self.controlArea, "Jittering") gui.comboBox(box, self, "jitter_value", items=["None", "0.01%", "0.1%", "0.5%", "1%", "2%"], callback=self._invalidate_plot) box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) box = gui.widgetBox(self.controlArea, "Points") box.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) self.colorvar_model = itemmodels.VariableListModel(parent=self) self.shapevar_model = itemmodels.VariableListModel(parent=self) self.sizevar_model = itemmodels.VariableListModel(parent=self) self.labelvar_model = itemmodels.VariableListModel(parent=self) form = QtGui.QFormLayout( formAlignment=Qt.AlignLeft, labelAlignment=Qt.AlignLeft, fieldGrowthPolicy=QtGui.QFormLayout.AllNonFixedFieldsGrow, spacing=8 ) box.layout().addLayout(form) cb = gui.comboBox(box, self, "color_index", callback=self._on_color_change) cb.setModel(self.colorvar_model) form.addRow("Colors", cb) alpha_slider = QSlider( Qt.Horizontal, minimum=10, maximum=255, pageStep=25, tickPosition=QSlider.TicksBelow, value=self.alpha_value) alpha_slider.valueChanged.connect(self._set_alpha) form.addRow("Opacity", alpha_slider) cb = gui.comboBox(box, self, "shape_index", callback=self._on_shape_change) cb.setModel(self.shapevar_model) form.addRow("Shape", cb) cb = gui.comboBox(box, self, "size_index", callback=self._on_size_change) cb.setModel(self.sizevar_model) form.addRow("Size", cb) size_slider = QSlider( Qt.Horizontal, minimum=3, maximum=30, value=self.point_size, pageStep=3, tickPosition=QSlider.TicksBelow) size_slider.valueChanged.connect(self._set_size) form.addRow("", size_slider) toolbox = gui.widgetBox(self.controlArea, "Zoom/Select") toollayout = QtGui.QHBoxLayout() toolbox.layout().addLayout(toollayout) gui.auto_commit(self.controlArea, self, "auto_commit", "Commit") # Main area plot self.view = pg.GraphicsView(background="w") self.view.setRenderHint(QtGui.QPainter.Antialiasing, True) self.view.setFrameStyle(QtGui.QFrame.StyledPanel) self.viewbox = pg.ViewBox(enableMouse=True, enableMenu=False) self.viewbox.grabGesture(Qt.PinchGesture) self.view.setCentralItem(self.viewbox) self.mainArea.layout().addWidget(self.view) self.selection = PlotSelectionTool( self, selectionMode=PlotSelectionTool.Lasso) self.selection.setViewBox(self.viewbox) self.selection.selectionFinished.connect(self._selection_finish) self.zoomtool = PlotZoomTool(self) self.pantool = PlotPanTool(self) self.pinchtool = PlotPinchZoomTool(self) self.pinchtool.setViewBox(self.viewbox) self.continuous_palette = colorpalette.ContinuousPaletteGenerator( QtGui.QColor(220, 220, 220), QtGui.QColor(0, 0, 0), False ) self.discrete_palette = colorpalette.ColorPaletteGenerator(13) def icon(name): path = "icons/Dlg_{}.png".format(name) path = pkg_resources.resource_filename(widget.__name__, path) return QtGui.QIcon(path) actions = namespace( zoomtofit=QAction( "Zoom to fit", self, icon=icon("zoom_reset"), shortcut=QKeySequence(Qt.ControlModifier | Qt.Key_0), triggered=lambda: self.viewbox.setRange(QRectF(-1.05, -1.05, 2.1, 2.1))), zoomin=QAction( "Zoom in", self, shortcut=QKeySequence(QKeySequence.ZoomIn), triggered=lambda: self.viewbox.scaleBy((1 / 1.25, 1 / 1.25))), zoomout=QAction( "Zoom out", self, shortcut=QKeySequence(QKeySequence.ZoomOut), triggered=lambda: self.viewbox.scaleBy((1.25, 1.25))), select=QAction( "Select", self, checkable=True, icon=icon("arrow"), shortcut=QKeySequence(Qt.ControlModifier + Qt.Key_1)), zoom=QAction( "Zoom", self, checkable=True, icon=icon("zoom"), shortcut=QKeySequence(Qt.ControlModifier + Qt.Key_2)), pan=QAction( "Pan", self, checkable=True, icon=icon("pan_hand"), shortcut=QKeySequence(Qt.ControlModifier + Qt.Key_3)), ) self.addActions([actions.zoomtofit, actions.zoomin, actions.zoomout]) group = QtGui.QActionGroup(self, exclusive=True) group.addAction(actions.select) group.addAction(actions.zoom) group.addAction(actions.pan) actions.select.setChecked(True) currenttool = self.selection self.selection.setViewBox(None) def activated(action): nonlocal currenttool if action is actions.select: tool, cursor = self.selection, Qt.ArrowCursor elif action is actions.zoom: tool, cursor = self.zoomtool, Qt.ArrowCursor elif action is actions.pan: tool, cursor = self.pantool, Qt.OpenHandCursor else: assert False currenttool.setViewBox(None) tool.setViewBox(self.viewbox) self.viewbox.setCursor(QtGui.QCursor(cursor)) currenttool = tool group.triggered[QAction].connect(activated) def button(action): b = QtGui.QToolButton() b.setDefaultAction(action) return b toollayout.addWidget(button(actions.select)) toollayout.addWidget(button(actions.zoom)) toollayout.addWidget(button(actions.pan)) toollayout.addSpacing(4) toollayout.addWidget(button(actions.zoomtofit)) toollayout.addStretch() toolbox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)