Skip to content

Commit

Permalink
feat: add colorbar (close #1)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmueller committed Dec 2, 2019
1 parent 10b1ba3 commit 4ce0bdb
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 26 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
- feat: implement loading of (polygon) filters from file
- feat: implement session saving and opening
- feat: added perceptive colormaps and set viridis as default
- feat: allow to set hue range for feature-colored scatter plots
- feat: allow to set hue range for feature-colored scatter plots (#1)
- feat: add colorbar (#1)
- fix: hide confusing "Advances Export" plot menu in developer mode
- fix: only show scalar features in QuickView feature selection
- fix: QuickView -> Event -> Features labels in table were drawn
Expand Down
26 changes: 13 additions & 13 deletions shapeout2/gui/analysis/ana_plot.ui
Original file line number Diff line number Diff line change
Expand Up @@ -654,22 +654,22 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="1">
Expand Down
96 changes: 96 additions & 0 deletions shapeout2/gui/colorbar_widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import numpy as np
from PyQt5 import QtGui
import pyqtgraph as pg
from pyqtgraph.graphicsItems.GradientEditorItem import Gradients


class ColorBarWidget(pg.GraphicsWidget):
def __init__(self, cmap, width, height, vmin=0.0, vmax=1.0, label=""):
"""Colorbar widget that can be added to a layout
This widget can be added to a GraphicsLayout. It is designed to
work well with the Shape-Out plot layout.
Parameters
----------
cmap: str
Name of the colormap
width: int
Width of the colorbar
height:
Height of the colorbar
vmin: float
Lower value of the colorbar
vmax: float
Upper value of the colorbar
label: str
Label placed next to the colorbar
Notes
-----
Inspired by https://gist.github.com/maedoc/b61090021d2a5161c5b9
"""
pg.GraphicsWidget.__init__(self)
self.setSizePolicy(QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Preferred)

# arguments
pcmap = pg.ColorMap(*zip(*Gradients[cmap]["ticks"]))
w = width
h = height
stops, colors = pcmap.getStops('float')
smn, spp = stops.min(), stops.ptp()
stops = (stops - stops.min())/stops.ptp()
ticks = np.r_[0.0:1.0:5j, 1.0] * spp + smn
tick_labels = ["%0.2g" % (t,) for t in np.linspace(vmin, vmax, 5)]

# setup picture
self.pic = pg.QtGui.QPicture()
p = pg.QtGui.QPainter(self.pic)

# draw bar with gradient following colormap
p.setPen(pg.mkPen('k'))
grad = pg.QtGui.QLinearGradient(w/2.0, 0.0, w/2.0, h*1.0)
for stop, color in zip(stops, colors):
grad.setColorAt(1.0 - stop, pg.QtGui.QColor(*[c for c in color]))
p.setBrush(pg.QtGui.QBrush(grad))
p.drawRect(pg.QtCore.QRectF(0, 0, w, h))

# draw ticks & tick labels
mintx = 0.0
maxwidth = 0.0
for tick, tick_label in zip(ticks, tick_labels):
y_ = (1.0 - (tick - smn)/spp) * h
p.drawLine(w, y_, w+5.0, y_)
br = p.boundingRect(
0, 0, 0, 0, pg.QtCore.Qt.AlignRight, tick_label)
if br.x() < mintx:
mintx = br.x()
if br.width() > maxwidth:
maxwidth = br.width()
p.drawText(br.x() + 10.0 + w + br.width(),
y_ + br.height() / 4.0, tick_label)

# draw label
br = p.boundingRect(0, 0, 0, 0, pg.QtCore.Qt.AlignBottom, label)
p.rotate(90)
p.drawText(h/2 - br.width()/2, -w-maxwidth-15, label)

# done
p.end()

# set minimum sizes (how do you get the actual bounding rect?)
br = self.pic.boundingRect()
self.setMinimumWidth(br.width() + maxwidth + 20)
self.setMinimumHeight(h)

# alognment with other Shape-Out plots (kind of a workaround)
self.translate(0, 40)

def paint(self, p, *args):
# paint underlying mask
p.setPen(pg.QtGui.QColor(255, 255, 255, 0))
p.setBrush(pg.QtGui.QColor(255, 255, 255, 200))

# paint colorbar
p.drawPicture(0, 0, self.pic)
45 changes: 36 additions & 9 deletions shapeout2/gui/pipeline_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from ..pipeline import Plot
from .. import plot_cache
from .colorbar_widget import ColorBarWidget
from .simple_plot_widget import SimplePlotItem


Expand Down Expand Up @@ -50,13 +51,11 @@ def update_content(self):

# font size for plot title (default size + 2)
size = "{}pt".format(QtGui.QFont().pointSize() + 2)
self.plot_layout.addLabel(lay["name"], colspan=2, size=size)
self.plot_layout.addLabel(lay["name"], colspan=3, size=size)
self.plot_layout.nextRow()

self.plot_layout.addLabel(labely, angle=-90)
linner = self.plot_layout.addLayout()
self.plot_layout.nextRow()
self.plot_layout.addLabel(labelx, col=1)

# limits in case of scatter plot and feature hue
if lay["division"] == "merge":
Expand Down Expand Up @@ -107,6 +106,34 @@ def update_content(self):
colspan=1)
pp.redraw(dslist, slot_states, plot_state_contour)

sca = plot_state["scatter"]
colorbar_kwds = {}

if sca["marker hue"] == "kde":
colorbar_kwds["vmin"] = 0
colorbar_kwds["vmax"] = 1
colorbar_kwds["label"] = "density"
elif sca["marker hue"] == "feature":
colorbar_kwds["vmin"] = sca["hue min"]
colorbar_kwds["vmax"] = sca["hue max"]
feat = sca["hue feature"]
colorbar_kwds["label"] = dclab.dfn.feature_name2label[feat]

if colorbar_kwds:
# add colorbar
sca = plot_state["scatter"]
colorbar = ColorBarWidget(
cmap=sca["colormap"],
width=15,
height=min(300, lay["size y"]//2),
**colorbar_kwds
)
self.plot_layout.addItem(colorbar)

self.plot_layout.nextRow()
self.plot_layout.addLabel(labelx, col=1)
self.update()


class PipelinePlotItem(SimplePlotItem):
def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -329,14 +356,14 @@ def add_scatter(plot_item, plot_state, rtdc_ds, slot_state):
brush.append(cmap.mapToQColor(f))
elif sca["marker hue"] == "dataset":
alpha = int(sca["marker alpha"] * 255)
color = pg.mkColor(slot_state["color"])
color.setAlpha(alpha)
brush = pg.mkBrush(color)
colord = pg.mkColor(slot_state["color"])
colord.setAlpha(alpha)
brush = pg.mkBrush(colord)
else:
alpha = int(sca["marker alpha"] * 255)
color = pg.mkColor("k")
color.setAlpha(alpha)
brush = pg.mkBrush(color)
colork = pg.mkColor("#000000")
colork.setAlpha(alpha)
brush = pg.mkBrush(colork)

# convert to log-scale if applicable
if gen["scale x"] == "log":
Expand Down
7 changes: 4 additions & 3 deletions shapeout2/pipeline/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
DEFAULT_STATE = {
"identifier": "no default",
"layout": {
"column count": 3,
"column count": 2,
"division": "multiscatter+contour",
"label plots": True,
"name": "no default", # overridden by __init__
"size x": 500,
"size x": 600,
"size y": 400,
},
"general": {
Expand Down Expand Up @@ -72,7 +72,8 @@
"scale y": ["linear", "log"],
},
"scatter": {
"colormap": ["inferno", "jet", "magma", "plasma", "viridis"],
"colormap": ["flame", "inferno", "magma", "plasma", "thermal",
"viridis"],
"downsampling": bool,
"downsampling value": int,
"enabled": bool,
Expand Down

0 comments on commit 4ce0bdb

Please sign in to comment.