-
Notifications
You must be signed in to change notification settings - Fork 7
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
feat: Histogram Widget #52
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #52 +/- ##
==========================================
+ Coverage 78.93% 80.24% +1.30%
==========================================
Files 13 16 +3
Lines 1856 2237 +381
==========================================
+ Hits 1465 1795 +330
- Misses 391 442 +51 ☔ View full report in Codecov by Sentry. |
hey! This is super cool. I'm still in Italy, and will be slowly unburying myself after I return tomorrow. But will leave some scattered/disorganized thoughts here in the brief moments I have to look. |
honestly, I think this is pretty great! I could certainly make tiny little nitpicky comments or suggestions, but they all feel rather bike-sheddy. I like the design a lot. There are perhaps a few usability quirks when using various methods like since I don't have many concrete suggestions at the moment, you could just keep working on polishing things you know you wanted to work on. Or I could just keep playing with it and make tiny changes as I go that I could either push directly or in a sub-PR (sometimes that's easier for me than making github comments). great work 🚀 edit: will add minor things I find here:
|
in terms of alignment with #51, I'd say don't worry too much. I don't think that the LUTs signals are going to change all that dramatically; so whoever merges second can just make whatever little patches would be necessary if they diverge slightly |
oh, and by the way, I do think we should look into seeing what fastplotlib can provide for the pygfx side of things. beyond the package itself, it brings no additional dependencies (beyond stuff we already depend on), so it could simply be added to the |
@tlambert03 tell me what you think of 5a7097b. |
@tlambert03 any suggestions for resolving this
Note that the current situation draws complaints from |
I was already wondering whether using composition (rather than directly inheriting sceneCanvas) might work better, and I think that would maybe solve this too (but may add problems too, need to look closer) |
Still bugs aplenty, but at least this gives us an interactive testing opportunity to find them
Also includes an interactive example in x.py
@tlambert03 I've made some significant changes here, including your composition suggestion, and created an interactive example within |
Looking at fastplotlib, the library has a HistogramLUTTool, which is great, however:
Also, it's worth noting that the histogram does not provide the same customization as VisPy, which isn't a dealbreaker but is unfortunate. I ran out of time to determine whether a logarithmic axis is possible - guessing so, but didn't have time to find it. All of these points are based off of the latest version on PyPI right now - it's possible that the latest Starter example code below: # test_example = true
from math import pi
import fastplotlib as fpl
from fastplotlib.widgets.histogram_lut import HistogramLUT
import numpy as np
figure = fpl.Figure(size=(700, 560))
# cmap_transform from an array, so the colors on the sine line will be based on the sine y-values
data = np.random.normal(10, 10, 10000).reshape((100, 100))
ig = fpl.ImageGraphic(data)
h = HistogramLUT(data, ig)
h.rotate(-pi / 2, "z")
g = figure[0, 0].add_graphic(h)
figure.show()
# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively
# please see our docs for using fastplotlib interactively in ipython and jupyter
if __name__ == "__main__":
print(__doc__)
fpl.run() |
ok, that's great detail, thanks for looking into it. in that case, maybe we're better off vendoring/borrowing little bits more as a pattern of usage than a direct dependency |
I believe that general figure structure is still valuable and maybe worth the dependency, so I'm currently trying to hack together a |
just checking in here. here are things i think should happen before merge (and things that we don't need to do in this PR) need
at that point, I think I'd like to take a finer-tooth comb through it and make direct edits for a PR to your PR don't need here:
|
Yup, this is what I'm doing. I'm not sure what you mean by pinning the newlims to the min/max of the other value, and you could definitely convince me to change the behavior if you can maybe elaborate a bit more on what you want to do and why. The situation I'd like to avoid is struggling to grab the desired handle when the sliders overlap (this is what happens, for example, in the fastplotlib histogram). It's possible that we could solve this, as well as implement the behavior you're interested in, by making explicit handles that are dragged instead of the line, like what mmstudio offers.
👍 (also goes for testing/documentation/cleanup)
The only situation where I could see wanting to grab multiple things at once is if you wanted to "translate" the clims left/right (i.e. "grab both"). But we could make a separate enum for that, because you'd presumably want to specify that window with a separate object (like fastplotlib does).
Sure, I'll throw my current efforts onto a new branch.
That was actually mostly created as a visual test of the widget, and my plan (aligning with your suggestion) was to move it to an example. Good to have an explicit reminder though!
👍 |
It *seems* like this issue goes deeper than I first thought? I've got to be doing something wrong here...
@tlambert03 I added handles for adjusting the clims in 89161c4. I think that the Markers could use some manipulation, but this would solve both my frustration of being unable to distinguish between left and right clims when they are overlapped, and your frustration of the clims surprisingly "sliding" past each other. I'm not tied to the idea, but let me know what you think! |
f31dfb4
to
d7775ed
Compare
updates: - [github.com/abravalheri/validate-pyproject: v0.19 → v0.22](abravalheri/validate-pyproject@v0.19...v0.22) - [github.com/crate-ci/typos: v1.24.5 → v1.27.0](crate-ci/typos@v1.24.5...v1.27.0) - [github.com/astral-sh/ruff-pre-commit: v0.6.5 → v0.7.2](astral-sh/ruff-pre-commit@v0.6.5...v0.7.2) - [github.com/pre-commit/mirrors-mypy: v1.11.2 → v1.13.0](pre-commit/mirrors-mypy@v1.11.2...v1.13.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
If you're fine with it, let's just leave it the way it is then 😅
Rewrote history to remove that behavior, I tried my best to ensure your formatting changes made it through. |
great, thanks for that reversion. i'm noticing now that the tolerance of Untitled.mov |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couple more things I noticed here while playing with this:
- clim handles don't appear to work in vertical mode, but the gamma handle does.
- though it might seem a little confusing, I think the Y axis should be inverted in "vertical" mode: with negative values at the top, and positive values at the bottom (making it a 90˚ clockwise rotation of the horizontal plot). alternatively, the y axis could be on the right side, making it a 90˚ counter-clockwise rotation of the horizontal plot.
- in logarithmic mode, the Y axis also needs to be logarithmic, so that the apparent range of values doesn't change (i.e. if the peak value in the regular histogram is ~130, then it should still be 130 in logarithmic mode). that means we can't just apply the logarithm to the counts themselves without modifying the axis as well. Not sure if vispy supports this easily...
in all cases, I'm happy to just merge this now and have them fixed in a follow up PR. I've just invited you to the repo with write access, so feel free to merge this if you want to be done with it and move on to smaller incremental fixes :)
Nah, let's clean them up now, while we're still thinking about it:
Fixed in 71edf3c
Fixed in d5b4b6a
EDIT 2: See here for proof that it isn't supported 😅. EDIT 3: And more proof. Maybe we should try to push a fix upstream? |
yeah this. that's fine. future goal :)
sure ...future :) |
Until then, would you prefer axis text? |
tests have broken (in case you didn't notice) |
Ahh, sorry, I thought I had pushed the fix but instead it got caught up in a local-only WIP commit that added those axis labels in my screenshot above. Pushed now. |
Hi! Cool to see you guys using pygfx & fastplotlib 😄 . I just thought I'd add some thoughts. I want to refactor our histogram tool soon due to issues like fastplotlib/fastplotlib#673, fastplotlib/fastplotlib#645, so this is good timing! The current HistogramLUTTool was mainly created for the [ImageWidget](https://www.fastplotlib.org/ver/dev/_gallery/image_widget/image_widget.html#sphx-glr-gallery-image-widget-image- Log scales is on the roadmap for
I'm curious what additional functionality you require! I notice you subclassed the Unrelated to this PR, I notice you're also working on ROI tools with |
thanks for checking in here @kushalkolar! :) much appreciated |
Oh, that's great!
It's mostly just the things I described here:
The precomputed histogram feature is the one that's really important for us - the others would likely be simpler inclusions.
This is also good information, I'll have to take a look!
Yes, moving things upstream would be great. I know ROI that has implications for the histogram is a line ROI, as in MicroManager we often want to compute histograms on points along a line - I didn't see that on your issue, but maybe it's worth adding? |
This PR adds a standalone widget for creating histograms of datasets. This PR is limited in scope, as requested by @tlambert03 - it does not interface with ndv in any way.
This PR is designed for integration with #51, and adopts a MVC structure to fit with the components being built over there. The components are described below:
StatsModel
This component is designed to retain computed statistics from a provided dataset (right now, it's just the histogram, really, but we may want more later), and signal listeners when the dataset changes.
StatsView
This component contains the API to describe an object that wants to listen for changes to the
StatsModel
, and update some display of that data for observation. One example might be aQWidget
with some labels displaying mean and standard deviation, like exists in mmstudio.LutView
This component contains the API to describe an object that wants to listen for changes to a LUT being used to visualize values in a dataset, and to update some display of that data for observation. The current
ndv
LutControl
objects could be refactored into one of these. I believe that @tlambert03 has aLutModel
as a part of #51 - we should coordinate here to make sure the API lines up.HistogramView
This component is both a
StatsView
(because the histogram is a statistical feature of a dataset) and aLutView
(because it has controls for clims, gamma, etc.), with some extra API pertaining to histogram viewing.VispyHistogramView
This component is an implementation for
HistogramView
, backed by VisPy, and the real workhorse of the PR.If you run
x.py
, you'll see the following, which is aVispyHistogramView
that has been connected to aStatsModel
. Right now, there is no controller, because 🤷TODO
...I'm tired, but this will be an active list of wants/needs/dreams...