Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@tlambert03
Copy link
Contributor

Description

Still a lot that needs to be done, but I wanted to show a quick example of a working histogram widget. The widget is implemented using only vispy and Qt, and has 2-way data-binding with the contrast_limits and gamma sliders of a given layer. I know there's been discussion about how/where this sort of thing would go (drawer? dockable? etc...), and this widget is agnostic to those implementations.

ezgif-4-78395626efaa

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

How has this been tested?

  • need to write tests
  • all tests pass with my change

Final checklist:

  • My PR is the minimum possible work for the desired functionality
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works

@tlambert03 tlambert03 changed the title [WIP] Histogram with 2-way control [WIP] Histogram with 2-way LUT control Nov 10, 2019
@sofroniewn
Copy link
Contributor

This is phenomenal @tlambert03!! Very nice to see the histograms / line plots done with vispy, this makes me very excited about #516 and supporting more general 1D plotting in the main canvas.

We're also getting more and more requests for supporting multiple vispy canvases simultaneously, either for linked ortho-views, or a linked grid mode, or link image + timeseries displays. If we go down that road does it sense then to consider this histogram view as a special case of some of that stuff and display it in a second canvas next to / under the main image, rather then say in some entirely separate window.

I wouldn't want to hold this PR up unnecessarily though, and starting with it in a separate pop-up window might be the easiest, but curious about your thoughts around multi-canvas mode

@sofroniewn sofroniewn added the feature New feature or request label Nov 11, 2019
@sofroniewn sofroniewn added this to the 0.3.0 milestone Nov 11, 2019
@jni
Copy link
Member

jni commented Nov 11, 2019

Just dropping by to say 😍

@tlambert03
Copy link
Contributor Author

This is phenomenal @tlambert03!! Very nice to see the histograms / line plots done with vispy, this makes me very excited about #516 and supporting more general 1D plotting in the main canvas.

yeah, the canvas is pretty much a thin subclass on vispy's PlotWidget, which provides an example of linking the axes domains to the data and pan/zoom everything together. So it's nicely set up for 1D data. Part of what I want to do is refactor what I have here to make the histogram a subclass of a broader plot widget that could be easily reused.

does it sense then to consider this histogram view as a special case of [multiple-canvases] and display it in a second canvas next to / under the main image, rather then say in some entirely separate window.

possibly... One of the reasons I made it as a Qt widget instead of just a vispy canvas is to add some interactivity features (like the mouse cursor changing when you hover over the gamma or clim handles). I don't know how to do that in vispy alone (but it might be possible... or maybe the couple things requiring Qt aren't worth it and we can refactor). That said, the multi-canvas thing could potentially just be implemented as a QGridLayout, and it wouldn't really matter whether each item in the grid was a vispy canvas, or a QWidget (provided the widget had a black background and blended in seamlessly to the larger view)

I wouldn't want to hold this PR up unnecessarily though, and starting with it in a separate pop-up window might be the easiest, but curious about your thoughts around multi-canvas mode

I do think it's worth thinking about up front. If you guys feel like depending on Qt limits the flexibility of the 1D plotting "widget", let me know and I'll look into keeping it strictly as a vispy canvas. (at the possible cost of a bit of interactivity)

@jni
Copy link
Member

jni commented Nov 11, 2019

If you guys feel like depending on Qt limits the flexibility of the 1D plotting "widget", let me know and I'll look into keeping it strictly as a vispy canvas. (at the possible cost of a bit of interactivity)

I don't have a strong opinion about this, but imho having it be a Qt widget makes sense. I think @royerloic would prefer a drawer to a pop-up, but other than that it makes sense to have it be a Qt Widget right now. Let's just be careful to have a separate model with the required data, and the view/controller Qt stuff is fine.

@tlambert03
Copy link
Contributor Author

I think @royerloic would prefer a drawer to a pop-up, but other than that it makes sense to have it be a Qt Widget right now.

yeah I'd much prefer a drawer as well. I think napari should generally avoid pop-up glut.

@jni
Copy link
Member

jni commented Nov 11, 2019

I think napari should generally avoid pop-up glut.

It's one of our founding principles. =D

@tlambert03
Copy link
Contributor Author

It's one of our founding principles. =D

you have all the best founding principles 😉

@sofroniewn
Copy link
Contributor

I've got no problem with using the QWidget if that's a better way to get more interactivity than just the vispy canvas as I know people will want interactivity with this stuff (e.g. link up rectangle from a shapes layer over a 3D image layer to a 1-D line plot to show the average of the rectangle in the line plot as you move the rectangle, requested by @d-v-b).

I think we will also want to make sure that we keep some sense of model / view separation though, and maybe having some model of the histogram that has no vispy or Qt in it would be good, like we have done with our layer models.

Using the QGridLayout for the multicanvas stuff sounds good too, as does using a draw.

@royerloic
Copy link
Member

Great work @tlambert03 !

second @jni that we want to avoid popups and/or extra windows,
but this is of course a first attempt and so it is ok to temporarily
violate a founding principle ;-))

A few comments and ideas:
i) Our earlier thoughts for the histogram was indeed to have a drawer, the question is where... Most screens have strong landscape aspect ratios, so I would suggest to have the drawer on the right side, with the histogram rotated 90 deg.
ii) The histogram could slide open automatically as you change contrast and gamma parameters.
(just throwing the idea out, not sure about it).
iii) The LUT colors could be shown as a colored bar that spans the contrast interval on the Y axis, giving a clear readout from LUT value to values on the axis.
iv) Linked views can be a way to implement this that would help us set up more generic
machinery for linking 2D, 3D, line profiles, histograms and more...
v) I think the vispy multi-canvas might be too brittle and limited, we will have more freedom
and flexibility with multiple widgets.
vi) The axis and margins of the histogram might be a bit wastefull long-term, we might
have to tune that to have a more compact layout.
vii) Gamma and contrast-limits are a good part of the 'model' here, the histogram being 'linked-data' that should be updated at appropriate occasions.

@tlambert03
Copy link
Contributor Author

Thanks @royerloic for your helpful input! I added a vertical layout flag to the histogram... and will definitely add a LUT bar soon. I tried to tighten up the margins as much as possible; the layouts are pretty flexible and resize well to whatever space we put them in (the vertical orientation still feels a bit weird but that can change). I also added some logic to link the histogram model to the viewer.active_layer so that it links and unlinks from the layer events upon switching. You can also have it calculate the histogram just on the current view slice (which will obviously be necessary for very large data): you'll see that towards the end of the gif, where the bottom widget is in view mode and the vertical histogram is in full stack data mode.

ezgif-4-7f15f7ee92f0

I also started to abstract some of the ideas into a more general QtPlotWidget today - trying to follow your general MVC pattern - and I think it's got potential, but it's also possible that I've over-complicated things and/or started wandering into territory for which you already have a clear vision (like your plugin architecture), so I would love your thoughts/criticisms/warnings on it when you have time... Here's what I'm currently thinking/doing for "plottable" things:

  1. some underlying analysis model (here, components.histogram.Histogram) has a set_data method and does something interesting with it.
  2. some VispyPlotLayer is responsible for linking a napari layer with the analysis model, (feeding it either some/or all of the data) and turning the output into a vispy node that can be plotted in the NapariPlotWidget (which is a gridded vispy scene that has AxisWidgets and a main ViewBox ready for plot nodes).
  3. The QtPlotWidget wraps the PlotWidget, and has a convenience methods (like converting between plot coordinates and window coordinates on mouseover or resize). Subclasses of it like QtHistogramWidget add VispyPlotLayer-specific functionality. (It's also possible that we don't subclass the QtPlotWidget, but rather use composition somehow to deliver and remove plot nodes from QtPlotWidget.plot.view).

@codecov
Copy link

codecov bot commented Dec 14, 2019

Codecov Report

Merging #675 into master will decrease coverage by 2.55%.
The diff coverage is 2.4%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #675      +/-   ##
==========================================
- Coverage   82.87%   80.32%   -2.56%     
==========================================
  Files         152      159       +7     
  Lines       15295    15785     +490     
==========================================
+ Hits        12676    12679       +3     
- Misses       2619     3106     +487
Impacted Files Coverage Δ
napari/_vispy/vispy_plot.py 0% <0%> (ø)
napari/_vispy/cameras.py 0% <0%> (ø)
napari/_qt/qt_plot_widget.py 0% <0%> (ø)
napari/_vispy/vispy_histogram.py 0% <0%> (ø)
napari/components/histogram.py 0% <0%> (ø)
napari/_qt/qt_lineprofile.py 0% <0%> (ø)
napari/_qt/qt_histogram.py 0% <0%> (ø)
napari/util/misc.py 96.05% <100%> (+0.27%) ⬆️
napari/_qt/layers/qt_image_base_layer.py 86.76% <100%> (-0.2%) ⬇️
napari/util/event.py 61.22% <0%> (-0.35%) ⬇️
... and 7 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9ba2e7f...0cbb95d. Read the comment docs.

@imagesc-bot
Copy link

This pull request has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/missing-features/41518/3

@tlambert03 tlambert03 closed this Sep 9, 2020
@dongyaoli10x
Copy link
Contributor

Hi @tlambert03, I am wondering if there are plans to further some of the good works you did here. Plotting infrastructure, including live plotting, would be very useful for the dock_widget plugins.

@tlambert03
Copy link
Contributor Author

hi @dongyaoli10x,
This is a tough one. On the one hand, I really liked the functionality here (fast, opengl-based basic plotting provided by vispy, without any new dependencies)... but the real challenge, and the thing that eventually led us to delay this indefinitely, is the API. I believe there is a slight fear that if we start providing convenience functions to build plots, then it's not clear where that "ends", and we don't want to duplicate plotting libraries.
That said, a lot of time has passed, I can still see a lot of usefulness coming out of provided some wrapper around the vispy PlotWidget, (like the NapariPlotWidget) in this PR. And with the magicgui-backed functional widgets now, I can also imagine supporting basic line, bar & scatter plotting based on function return annotations.
Anyway, it's a huge topic with a lot of potential (and a lot of work!). Thanks for bringing it up again, curious what @sofroniewn and @jni think about this general area these days.

@sofroniewn
Copy link
Contributor

Anyway, it's a huge topic with a lot of potential (and a lot of work!). Thanks for bringing it up again, curious what @sofroniewn and @jni think about this general area these days.

One option that we have available to us as of 0.4.3 it to start making a napari-plots plugin. It could be its own repo, could be backed by either vispy and/or matplotlib and/or other plotting libraries and leverage the provide_dock_widget hookspec. This approach would allow us to rapidly iterate (we could have low expectations on API stability there for a couple of releases even), would keep the plotting functionality separate from the image functionality.

If we love the direction its going then maybe we fold the repo into master or maybe just make it a required dependency.

And with the magicgui-backed functional widgets now, I can also imagine supporting basic line, bar & scatter plotting based on function return annotations.

I love this idea too!!! Could be done in this new repo also.

@jni
Copy link
Member

jni commented Jan 19, 2021

Yep, I love love love the idea of a napari-plots plugin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants