-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Add textbook-like tutorial on measuring fluorescence at nuclear envelope. #5262
Add textbook-like tutorial on measuring fluorescence at nuclear envelope. #5262
Conversation
👋 @mkcor this is very exciting. =) I don't think for this tutorial it's needed because the nuclei are not close together (?), but I just want to give a shout-out to @VolkerH's |
Thank you for the great suggestion, @jni! I decided to go for @VolkerH's expand = segmentation.expand_labels(label)
dilate = morphology.dilation(label) (where The rim is then about 2px-thick (I zoomed in with Plotly to check). But I tried reproducing the original processing faithfully, and it's straightforward with expand = segmentation.expand_labels(label, distance=4) where I can just expand more, as much as I like! 😄 |
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.
Hi @mkcor ,
super cool to see this evolving, thanks for working on this! As I translated the workflow at some point as well, I was curious and took a look at your implementation. I found some differences compared to the original implementation. I don't want to be picky; I was just wondering if you made those changes intentionally and if so, why. :-) Also did you compare quantitative measurements with the measurements generated with your script? You find quantitative measurements from the original workflow in ImageJ for example here and from an alternative implementation here.
Also one more minor comment: I personally prefer variable names such as "input_image" over "dat". Also "channel_0_image" could be more self-explanatory than "ch0t0". But maybe I'm just too used to writing longVariableNamesInJava
;-)
Great work otherwise! Many biologists will appreciate this example in scikit-image and the detailed explanation of the used commands.
Thanks again!
Best,
Robert
|
||
smooth = filters.gaussian(ch0t0, sigma=2) | ||
|
||
thresh = smooth > 0.1 |
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.
In the original workflow Otsu's threshold method was used. Is there a reason why we're using a fixed constant threshold here?
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.
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.
Fixed in 02c2823.
"Reassuringly, we find the expected result: The total fluorescence intensity at the nuclear envelope increases 1.3-fold in the initial five time points, and then becomes roughly constant."
Now that I'm more consistent with the original workflow, the overall result is preserved but, comparing with the textbook plot, we can see sharper dips (below 1.2) for time points 7 and 12:
|
||
thresh = smooth > 0.1 | ||
|
||
fill = ndi.binary_fill_holes(thresh) |
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.
Also this step is not in the original workflow. I could imagine that it's not necessary if one uses Otsu's thresholding method...
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.
Right, well, this was always a bit of a mystery to me... Looking at steps c) and d), I've wondered how the small holes were handled: Does dilation automatically take care of filling them?
I don't see what difference using Otsu's thresholding method would make (see above #5262 (comment))... Even with multi-Otsu thresholding (defaulting to 3 classes), and keeping the lower threshold, there are still small holes inside the main region:
|
||
##################################################################### | ||
# Although it is not strictly necessary, let us discard the other nucleus part | ||
# visible in the bottom right-hand corner. |
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.
In ImageJ macro, we're using the function of the Particle Analyzer for removing objects that touch the image border. How about using clear_border? I could imagine that the script becomes then more applicable also to other images and use-cases.
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.
Great point! Your suggestion is much more readable and much more elegant than what I had; done 3c99e28.
label_small = regions['label'][np.argmin(regions['area'])] | ||
label[label == label_small] = 0 # background value | ||
|
||
expand = segmentation.expand_labels(label, distance=4) |
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.
In the original workflow, we erode the mask and dilate it, which means in ImageJ to take one pixel as radius.
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.
# Segment the nucleus rim | ||
# ======================= | ||
|
||
smooth = filters.gaussian(ch0t0, sigma=2) |
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.
In the original workflow sigma=1.5
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.
Thanks for pointing me to the ImageJ Macro source! I admit I didn't look it up; I followed the book chapter mostly qualitatively, but let's try and get as close as possible quantitatively...
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.
Fixed in 02c2823.
assert props['label'] == 1 | ||
intensity_total = props['area'] * props['intensity_mean'] | ||
fluorescence_change.append(intensity_total) | ||
|
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.
You could mention here that the following part is not in the original workflow. But as we are in python, we can do plotting and image analysis together in one script. :-)
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.
Hmm, the conclusion reads "Here, to summarize the analysis in this chapter, we plot the changes in the total fluorescence intensity over time using ImageJ Macro code_plotResults.ijm
(◘ Fig. 2.8). The code appears after the paragraph below."
So, I get that it's not part of the 'original workflow' but that's not because ImageJ would be limiting; is it?
Alternatively, I could change my introduction to make it explicit that I'm following this book chapter in particular, which itself is based on the original workflow.
@haesleinhuepf @jni please review: https://2809-2014929-gh.circle-artifacts.com/0/doc/build/html/auto_examples/applications/plot_fluorescence_nuclear_envelope.html The CI failures come from dat = imageio.volread('http://cmci.embl.de/sampleimages/NPCsingleNucleus.tif') where |
Hey @mkcor , sorry, I was too fast with the review :-D
The image was made by Andrea Boni (I can give you his email, if you tell me yours, or via zulip or twitter or something) . You can ask him for permission and then also download it here if you like. |
Hi @haesleinhuepf, Wow! You've been lightning fast and our comments have crossed! Thank you so much for your review. Please be picky! 😉
I hear you. In this case, would you agree with either |
This sounds great! :-) |
Thank you, @haesleinhuepf! I can see there is data provenance info here, but there is no explicit licensing info... We prefer using datasets which are in the public domain or under CC0: https://gitlab.com/scikit-image/data/#data Can you read my email address on my GitHub profile? |
@haesleinhuepf how about |
Sure. Sounds good :-) |
Or maybe |
This is ready for final review, thanks! /cc @hmaarrfk 😉 |
Okay, I will review this soon. I think it should be fine to add in 0.19.2 since it is just supplementing docs and not changing behavior of existing functions. |
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.
Thank you @mkcor, I added a small comment concerning the step labels in the first figure's titles, suggested to tighten figure's layout and proposed few minor code style modifications.
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
Co-authored-by: Riadh Fezzani <rfezzani@gmail.com>
Co-authored-by: Riadh Fezzani <rfezzani@gmail.com>
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.
This looks pretty nice @mkcor. I suggested some minor efficiency improvements that hopefully don't detract from readability. I will go ahead and approve as they are suggestions and don't change the final result.
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
doc/examples/applications/plot_fluorescence_nuclear_envelope.py
Outdated
Show resolved
Hide resolved
Co-authored-by: Gregory Lee <grlee77@gmail.com>
The CI failure is unrelated to this PR. It comes from another gallery example, namely the one on image stitching: Warning, treated as error:
/home/runner/work/scikit-image/scikit-image/doc/examples/registration/plot_stitching.py failed to execute correctly: Traceback (most recent call last):
[...]
File "/home/runner/work/scikit-image/scikit-image/doc/examples/registration/plot_stitching.py", line 110, in <listcomp>
trfm_list = [measure.ransac((dst, src),
AttributeError: 'NoneType' object has no attribute 'params' where the full code is: trfm_list = [measure.ransac((dst, src),
transform.EuclideanTransform, min_samples=3,
residual_threshold=2, max_trials=100)[0].params
for dst in matching_corners] But it's weird that the list of /cc @rfezzani |
Let me repeat the failing case and see if it resolves itself. I'm pretty sure I've seen that same failure happen at least once before. Maybe we need to fix a random seed or something? (not in this PR) |
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.
LGTM, thanks!
@meeseeksdev backport to v0.19.x |
…g fluorescence at nuclear envelope.
…2-on-v0.19.x Backport PR #5262 on branch v0.19.x (Add textbook-like tutorial on measuring fluorescence at nuclear envelope.)
Description
This draft PR fits the overall goal of offering more gallery examples for the life sciences (see #4601).
Here I'm following this amazing suggestion by @haesleinhuepf: https://forum.image.sc/t/looking-for-life-scientists-to-collaborate-on-scikit-image-tutorials/49073/15
Checklist
./doc/examples
(new features only)./benchmarks
, if your changes aren't covered by anexisting benchmark
For reviewers
later.
__init__.py
.doc/release/release_dev.rst
.