Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] 1D PlotWidget #823

Closed
wants to merge 65 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
838b698
just starting
tlambert03 Nov 9, 2019
f26a32f
basic working example
tlambert03 Nov 10, 2019
061a9b7
Merge branch 'master' into histogram
tlambert03 Nov 11, 2019
ed2faa3
starting to decompose into parts
tlambert03 Nov 11, 2019
f263c8e
Merge branch 'master' into histogram
tlambert03 Nov 11, 2019
d7e55ce
working ok with vertical and horizontal
tlambert03 Nov 11, 2019
9ce527c
add link param to qtviewer
tlambert03 Nov 12, 2019
2749cb1
Freedman Diaconis Estimator
tlambert03 Nov 12, 2019
0ad7f83
improved lutline visuals
tlambert03 Nov 12, 2019
fcf841f
signal_blocker context manager
tlambert03 Nov 12, 2019
bf1dfa1
Merge branch 'master' into histogram
tlambert03 Nov 12, 2019
3d29640
Merge branch 'master' of https://github.com/napari/napari into histogram
tlambert03 Nov 12, 2019
cda7b12
up and down arrows
tlambert03 Nov 13, 2019
0c4cd72
add log slider to histogram
tlambert03 Nov 13, 2019
3163438
updated styles for plotwidget
tlambert03 Nov 13, 2019
6172219
Merge branch 'master' into histogram
tlambert03 Nov 13, 2019
1ac0346
fix vertical scrollbar style
tlambert03 Nov 13, 2019
6199d0d
line profile example
tlambert03 Nov 14, 2019
853834d
Merge branch 'master' into histogram
tlambert03 Nov 18, 2019
1e88b50
vispy_dock bug example
tlambert03 Nov 20, 2019
b4bfcc1
Merge branch 'master' into histogram
tlambert03 Nov 23, 2019
1e482a1
Merge branch 'master' into histogram
tlambert03 Nov 23, 2019
ca6111a
pass through keypresses
tlambert03 Nov 23, 2019
aa1c1f2
preserve features on DockWidget
tlambert03 Nov 23, 2019
a6f571f
dockable layers list
sofroniewn Nov 23, 2019
a31b3de
restrict areas
sofroniewn Nov 23, 2019
b753201
Merge branch 'master' into dockable_layer_list
sofroniewn Nov 25, 2019
e92cba5
improve sizings
sofroniewn Nov 25, 2019
234bcdb
allow features to be reset after __init__
tlambert03 Nov 25, 2019
fa89857
trying titleBarWidget
tlambert03 Nov 25, 2019
9c64ffb
merge master
sofroniewn Nov 30, 2019
c90f440
Merge branch 'dockable_layer_list' of https://github.com/sofroniewn/n…
tlambert03 Dec 1, 2019
2052087
generally working minimal dockwidget
tlambert03 Dec 1, 2019
0a9f728
update styles
tlambert03 Dec 2, 2019
1ed84a3
good style behavior, needs code check
tlambert03 Dec 6, 2019
830fa50
Merge branch 'master' into pr/sofroniewn/727
tlambert03 Dec 7, 2019
50ba4fc
require parent on MinimalTitleBar
tlambert03 Dec 7, 2019
f414d10
add a couple pixels of padding between slider and console line
tlambert03 Dec 7, 2019
bff6f72
remove 1px left margin on vert titlebar
tlambert03 Dec 7, 2019
428c1cb
add float icon to titlebar
tlambert03 Dec 8, 2019
5a4a3b5
one dockwidget class to rule them all
tlambert03 Dec 8, 2019
aca69a5
Merge branch 'master' into pr/sofroniewn/727
tlambert03 Dec 8, 2019
7bab654
fix colorbarlabel
tlambert03 Dec 8, 2019
1fe4732
Merge branch 'master' into histogram
tlambert03 Dec 8, 2019
c361e49
remove palette from PlotWidget
tlambert03 Dec 8, 2019
f379ea3
Merge branch 'pr/sofroniewn/727' into histogram
tlambert03 Dec 8, 2019
7eeaa8f
bugfix in is_vertical
tlambert03 Dec 8, 2019
c6489c7
Merge branch 'pr/sofroniewn/727' into histogram
tlambert03 Dec 8, 2019
e3fcd77
bugfix after merge
tlambert03 Dec 8, 2019
1b1f1a2
fix icons
tlambert03 Dec 8, 2019
a134c4b
Merge branch 'pr/sofroniewn/727' into histogram
tlambert03 Dec 8, 2019
acd6b04
tweak histogram example
tlambert03 Dec 8, 2019
991c29c
incorporate nick's comments
tlambert03 Dec 8, 2019
c56275f
slight fix to pop_out icon, add tooltips
tlambert03 Dec 8, 2019
82ff95e
Merge branch 'pr/sofroniewn/727' into histogram
tlambert03 Dec 8, 2019
0cbb95d
Merge branch 'master' into histogram
tlambert03 Dec 14, 2019
7ca74b7
remove colorbar
tlambert03 Dec 15, 2019
411c625
Merge branch 'master' into histogram
tlambert03 Dec 15, 2019
85420d1
Merge branch 'master' into histogram
tlambert03 Dec 20, 2019
16f2add
remove histogram stuff
tlambert03 Dec 20, 2019
5d40302
Merge branch 'master' into plotwidget
tlambert03 Jan 11, 2020
68ecea7
mostly adding documentation
tlambert03 Jan 11, 2020
fab9556
lint fixes
tlambert03 Jan 11, 2020
cb83821
trimmed down
tlambert03 Jan 12, 2020
ccdb15c
add scatter and example
tlambert03 Jan 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions examples/colocalization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import numpy as np
from skimage import data
from skimage.color import rgb2hed
from scipy.stats import linregress


import napari

ihc_rgb = data.immunohistochemistry()
ihc_hed = rgb2hed(ihc_rgb)

with napari.gui_qt():
viewer = napari.Viewer()
viewer.add_image(ihc_hed[..., ::2], channel_axis=-1)
# add a docked figure
fig, dw = viewer.window.add_docked_figure()
# get a handle to the plotWidget
ax = fig[0, 0]

# calculate some data
x, y = ihc_hed[..., 0].ravel(), ihc_hed[..., 2].ravel()
data = np.array((x, y)).T
slope, intercept, r_value, p_value, std_err = linregress(x, y)
linex = np.linspace(x.min(), x.max(), 200)
liney = slope * linex + intercept

# plot the scatter plot and line
ax.plot((linex, liney), color='g', marker_size=0, width=2)
ax.scatter(data, size=2, edge_width=0, face_color='m')
viewer.window._qt_window.setGeometry(400, 100, 800, 900)
53 changes: 53 additions & 0 deletions examples/mouse_drag_callback_lineprofile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
Example updating the status bar with line profile info while dragging
lines around in a shapes layer.
"""

from skimage import data
from skimage import measure
import numpy as np
import napari
from napari._vispy import Fig


def get_line_data(image, start, end):
return measure.profile_line(image, start, end)


with napari.gui_qt():
np.random.seed(1)
viewer = napari.Viewer()
chelsea = data.chelsea().mean(-1)
viewer.add_image(chelsea)
shapes_layer = viewer.add_shapes(
[np.array([[11, 13], [250, 313]]), np.array([[100, 10], [10, 345]])],
shape_type='line',
edge_width=5,
edge_color='coral',
face_color='royalblue',
)
shapes_layer.mode = 'select'

# add the figure as a dock_widget
fig, dw = viewer.window.add_docked_figure(area='right', initial_width=250)
# add a new subplot to the figure for each line in the shapes layer
lines = [
fig[i, 0].plot(get_line_data(chelsea, *line), marker_size=0)
for i, line in enumerate(shapes_layer.data)
]

# hook the lines up to events
def profile_lines(image, shape_layer):
# only a single line for this example
for i, line in enumerate(shape_layer.data):
if i in shape_layer._selected_data:
lines[i].set_data(get_line_data(image, *line))
fig[i, 0].autoscale()

@shapes_layer.mouse_drag_callbacks.append
def profile_lines_drag(layer, event):
profile_lines(chelsea, layer)
yield
while event.type == 'mouse_move':
profile_lines(chelsea, layer)
yield
51 changes: 51 additions & 0 deletions examples/vispy_dock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
An example of a rendering bug using QDockWidgets
"""

import sys
import numpy as np

from vispy import scene, plot

from qtpy.QtCore import Qt, QSize
from qtpy import QtWidgets


class QtPlotWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.canvas = scene.SceneCanvas(bgcolor='k', keys=None, vsync=True)
self.canvas.native.setMinimumSize(QSize(300, 100))
self.setLayout(QtWidgets.QHBoxLayout())
self.layout().addWidget(self.canvas.native)
_ = scene.visuals.Line(
pos=np.array([[0, 0], [700, 500]]),
color='w',
parent=self.canvas.scene,
)

# self.plot = self.canvas.central_widget.add_widget(
# plot.PlotWidget(fg_color='w')
# )
# self.plot.histogram(np.random.randn(10000), bins=100, color='b')
# the histogram is just an example, but the axes alone are sufficient:
# self.plot._configure_2d()


class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.resize(700, 500)
dock_widget = QtWidgets.QDockWidget(self)
self.plot = QtPlotWidget()
dock_widget.setWidget(self.plot)
self.addDockWidget(Qt.BottomDockWidgetArea, dock_widget)


if __name__ == '__main__':
# import vispy
# print(vispy.sys_info())
appQt = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
appQt.exec_()
33 changes: 33 additions & 0 deletions napari/_qt/qt_main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ def add_dock_widget(
area: str = 'bottom',
allowed_areas=None,
shortcut=None,
initial_width=None,
initial_height=None,
):
"""Convenience method to add a QDockWidget to the main window

Expand All @@ -203,13 +205,28 @@ def add_dock_widget(
By default, all areas are allowed.
shortcut : str, optional
Keyboard shortcut to appear in dropdown menu.
initial_width : int, optional
Initial width for the docket widget.
initial_height : int, optional
Initial height for the docket widget.

Returns
-------
dock_widget : QtViewerDockWidget
`dock_widget` that can pass viewer events.
"""

if not isinstance(widget, QWidget):
if hasattr(widget, 'native') and isinstance(
widget.native, QWidget
):
widget = widget.native
else:
raise TypeError(
"widget must be a QWidget or vispy widget."
f" Got: {type(widget)}"
)

dock_widget = QtViewerDockWidget(
self.qt_viewer,
widget,
Expand All @@ -218,9 +235,25 @@ def add_dock_widget(
allowed_areas=allowed_areas,
shortcut=shortcut,
)

self._add_viewer_dock_widget(dock_widget)
if initial_width:
self._qt_window.resizeDocks(
[dock_widget], [initial_width], Qt.Horizontal
)
if initial_height:
self._qt_window.resizeDocks(
[dock_widget], [initial_height], Qt.Vertical
)
return dock_widget

def add_docked_figure(self, **kwargs):
from .._vispy import Fig

fig = Fig()
dw = self.add_dock_widget(fig, **kwargs)
return fig, dw

def _add_viewer_dock_widget(self, dock_widget: QtViewerDockWidget):
"""Add a QtViewerDockWidget to the main window

Expand Down
2 changes: 2 additions & 0 deletions napari/_vispy/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from .utils import create_vispy_visual
from .vispy_plot import PlotWidget
from .vispy_figure import Fig
30 changes: 30 additions & 0 deletions napari/_vispy/cameras.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from vispy.scene.cameras import PanZoomCamera
import numpy as np


class PanZoom1DCamera(PanZoomCamera):
def __init__(self, axis=1, *args, **kwargs):
"""A camera that can only Pan/Zoom along one axis.

Useful in a PlotWidget.

Parameters
----------
axis : int, optional
The axis to constrain. (This axis will NOT pan or zoom).
0 => lock x axis
1 => lock y axis
by default 1
"""
self.axis = axis
super().__init__(*args, **kwargs)

def zoom(self, factor, center=None):
if np.isscalar(factor):
factor = [factor, factor]
factor[self.axis] = 1
return super().zoom(factor, center=center)

def pan(self, pan):
pan[self.axis] = 0
self.rect = self.rect + pan
30 changes: 30 additions & 0 deletions napari/_vispy/vispy_figure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from vispy.plot.fig import Fig as VispyFig

from .vispy_plot import PlotWidget


class Fig(VispyFig):
"""Subclas of vispy.plot.Fig mostly just to use our internal plot widget.
"""

def __init__(
self,
bgcolor='k',
size=(800, 600),
show=True,
keys=None,
vsync=True,
**kwargs,
):
self._plot_widgets = []
self._grid = None # initialize before the freeze occurs
super(VispyFig, self).__init__(
bgcolor=bgcolor,
keys=keys,
show=show,
size=size,
vsync=vsync,
**kwargs,
)
self._grid = self.central_widget.add_grid()
self._grid._default_class = PlotWidget