def colors(data, variable, palette=None): if palette is None: if is_discrete(variable): palette = colorpalette.ColorPaletteGenerator(len(variable.values)) elif is_continuous(variable): palette = colorpalette.ColorPaletteBW() palette = colorpalette.ContinuousPaletteGenerator( QtGui.QColor(220, 220, 220), QtGui.QColor(0, 0, 0), False) else: raise TypeError() x = numpy.array(data[:, variable]).ravel() if is_discrete(variable): nvalues = len(variable.values) x[numpy.isnan(x)] = nvalues color_index = palette.getRGB(numpy.arange(nvalues + 1)) # Unknown values as gray # TODO: This should already be a part of palette color_index[nvalues] = (128, 128, 128) colors = color_index[x.astype(int)] else: x, _ = scaled(x) mask = numpy.isnan(x) colors = numpy.empty((len(x), 3)) colors[mask] = (128, 128, 128) colors[~mask] = [palette.getRGB(v) for v in x[~mask]] # colors[~mask] = interpolate(palette, x[~mask], left=Qt.gray) return colors
def continuous_colors(data, palette=None): if palette is None: palette = colorpalette.ContinuousPaletteGenerator( QtGui.QColor(220, 220, 220), QtGui.QColor(0, 0, 0), False ) amin, amax = numpy.nanmin(data), numpy.nanmax(data) span = amax - amin data = (data - amin) / (span or 1) mask = numpy.isnan(data) # Unknown values as gray # TODO: This should already be a part of palette colors = numpy.empty((len(data), 3)) colors[mask] = (128, 128, 128) colors[~mask] = [palette.getRGB(v) for v in data[~mask]] return colors
class mdsplotutils(plotutils): NoFlags, Selected, Highlight = 0, 1, 2 NoFill, Filled = 0, 1 plotstyle = namespace( selected_pen=make_pen(Qt.yellow, width=3, cosmetic=True), highligh_pen=QtGui.QPen(Qt.blue, 1), selected_brush=None, default_color=QtGui.QColor(Qt.darkGray).rgba(), discrete_palette=colorpalette.ColorPaletteGenerator(), continuous_palette=colorpalette.ContinuousPaletteGenerator( QtGui.QColor(220, 220, 220), QtGui.QColor(0, 0, 0), False ), symbols=ScatterPlotItem.Symbols, point_size=10, min_point_size=5, ) @staticmethod def column_data(table, var, mask=None): col, _ = table.get_column_view(var) dtype = float if var.is_primitive() else object col = numpy.asarray(col, dtype=dtype) if mask is not None: mask = numpy.asarray(mask, dtype=bool) return col[mask] else: return col @staticmethod def color_data(table, var=None, mask=None, plotstyle=None): N = len(table) if mask is not None: mask = numpy.asarray(mask, dtype=bool) N = numpy.count_nonzero(mask) if plotstyle is None: plotstyle = mdsplotutils.plotstyle if var is None: col = numpy.zeros(N, dtype=float) color_data = numpy.full(N, plotstyle.default_color, dtype=object) elif var.is_primitive(): col = mdsplotutils.column_data(table, var, mask) if var.is_discrete: palette = plotstyle.discrete_palette if len(var.values) >= palette.number_of_colors: palette = colorpalette.ColorPaletteGenerator(len(var.values)) color_data = plotutils.discrete_colors( col, nvalues=len(var.values), palette=palette) elif var.is_continuous: color_data = plotutils.continuous_colors( col, palette=plotstyle.continuous_palette) else: raise TypeError("Discrete/Continuous variable or None expected.") return color_data @staticmethod def pen_data(basecolors, flags=None, plotstyle=None): if plotstyle is None: plotstyle = mdsplotutils.plotstyle pens = numpy.array( [mdsplotutils.make_pen(QtGui.QColor(*rgba), width=1) for rgba in basecolors], dtype=object) if flags is None: return pens selected_mask = flags & mdsplotutils.Selected if numpy.any(selected_mask): pens[selected_mask.astype(bool)] = plotstyle.selected_pen highlight_mask = flags & mdsplotutils.Highlight if numpy.any(highlight_mask): pens[highlight_mask.astype(bool)] = plotstyle.hightlight_pen return pens @staticmethod def brush_data(basecolors, flags=None, plotstyle=None): if plotstyle is None: plotstyle = mdsplotutils.plotstyle brush = numpy.array( [mdsplotutils.make_brush(QtGui.QColor(*c)) for c in basecolors], dtype=object) if flags is None: return brush fill_mask = flags & mdsplotutils.Filled if not numpy.all(fill_mask): brush[~fill_mask] = QtGui.QBrush(Qt.NoBrush) return brush @staticmethod def shape_data(table, var, mask=None, plotstyle=None): if plotstyle is None: plotstyle = mdsplotutils.plotstyle N = len(table) if mask is not None: mask = numpy.asarray(mask, dtype=bool) N = numpy.nonzero(mask) if var is None: return numpy.full(N, "o", dtype=object) elif var.is_discrete: shape_data = mdsplotutils.column_data(table, var, mask) maxsymbols = len(plotstyle.symbols) - 1 validmask = numpy.isfinite(shape_data) shape = shape_data % (maxsymbols - 1) shape[~validmask] = maxsymbols # Special symbol for unknown values symbols = numpy.array(list(plotstyle.symbols)) shape_data = symbols[numpy.asarray(shape, dtype=int)] if mask is None: return shape_data else: return shape_data[mask] else: raise TypeError() @staticmethod def size_data(table, var, mask=None, plotstyle=None): if plotstyle is None: plotstyle = mdsplotutils.plotstyle N = len(table) if mask is not None: mask = numpy.asarray(mask, dtype=bool) N = numpy.nonzero(mask) if var is None: return numpy.full(N, plotstyle.point_size, dtype=float) else: size_data = mdsplotutils.column_data(table, var, mask) size_data = mdsplotutils.normalized(size_data) size_mask = numpy.isnan(size_data) size_data = size_data * plotstyle.point_size + \ plotstyle.min_point_size size_data[size_mask] = plotstyle.min_point_size - 2 if mask is None: return size_data else: return size_data[mask] @staticmethod def legend_data(color_var=None, shape_var=None, plotstyle=None): if plotstyle is None: plotstyle = mdsplotutils.plotstyle if color_var is not None and not color_var.is_discrete: color_var = None assert shape_var is None or shape_var.is_discrete if color_var is None and shape_var is None: return [] if color_var is not None: palette = plotstyle.discrete_palette if len(color_var.values) >= palette.number_of_colors: palette = colorpalette.ColorPaletteGenerator(len(color_var.values)) else: palette = None symbols = list(plotstyle.symbols) if shape_var is color_var: items = [(palette[i], symbols[i], name) for i, name in enumerate(color_var.values)] else: colors = shapes = [] if color_var is not None: colors = [(palette[i], "o", name) for i, name in enumerate(color_var.values)] if shape_var is not None: shapes = [(QtGui.QColor(Qt.gray), symbols[i % (len(symbols) - 1)], name) for i, name in enumerate(shape_var.values)] items = colors + shapes return items @staticmethod def make_pen(color, width=1, cosmetic=True): pen = QtGui.QPen(color) pen.setWidthF(width) pen.setCosmetic(cosmetic) return pen @staticmethod def make_brush(color, ): return QtGui.QBrush(color, )
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.__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 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)