Skip to content

Commit

Permalink
Update this repo for changes when upstreaming to napari-workshop-temp…
Browse files Browse the repository at this point in the history
…lates (#4)

* switch to using features plus some typos

* function formatting

* update binder setup

* fix binder

* add missing websockify

* use JupyterLab binder interface by default

* fix config for jupyterlab

* more formatting fixes from JNI

* fix stray python line in  spot_detection.md

* update binder instructions for jupyterlab default

* add binder setupt to functions notebook

* remove duplicate dbus-x11

* fix stray backticks
  • Loading branch information
psobolewskiPhD authored Oct 15, 2024
1 parent 2647ed4 commit b6d9805
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 47 deletions.
4 changes: 3 additions & 1 deletion binder/apt.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
dbus-x11
firefox
xfce4
xfce4-panel
xfce4-session
xfce4-settings
xorg
xubuntu-icon-theme
tigervnc-standalone-server
tigervnc-xorg-extension
libegl1
libx11-xcb-dev
libglu1-mesa-dev
libxrender-dev
Expand Down
13 changes: 8 additions & 5 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ name: binder
channels:
- conda-forge
dependencies:
- python=3.9
- jupyter-server-proxy>=1.4
- python=3.11
- jupyterlab
- jupytext
- pip
- jupyterlab-myst
- napari
- pyqt
- jupyter-book
- websockify
- libxcb
- pip
- pip:
- jupyter-desktop-server
- jupyter-remote-desktop-proxy
3 changes: 0 additions & 3 deletions binder/postBuild

This file was deleted.

2 changes: 1 addition & 1 deletion napari-workshops/_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ logo: logo.ico
only_build_toc_files: true

launch_buttons:
notebook_interface : classic # The interface interactive links will activate ["classic", "jupyterlab"]
notebook_interface : "jupyterlab" # The interface interactive links will activate ["classic", "jupyterlab"]
binderhub_url : https://mybinder.org # The URL of the BinderHub (e.g., https://mybinder.org)

# Force re-execution of notebooks on each build.
Expand Down
8 changes: 3 additions & 5 deletions napari-workshops/launching_binder.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@ To open a notebook in Binder, click on the rocketship badge at the top of a note

![Binder badge shown in the "Bioimage visualization in Python" notebook](./resources/binder_button.png)

Just opening the notebook is not sufficient. Because napari is a desktop application, we need a "Desktop" tab to see the napari GUI interface. To do this we need to return to the Jupyter dashboard, by clicking the Jupyter logo (marked in red below) in the upper left.

![Jupyter logo tool-tip showing `dashboard`](./resources/jupyter_logo_dashboard.png)
This will open the notebook in Markdown format, but it will not be runnable. Further, because napari is a desktop application, we need a "Desktop" tab to see the napari GUI interface. To do this, close the Markdown notebook and return to the Jupyter launcher.

## Open desktop tab

In the Jupyter launcher tab, click on "Desktop".
In the Jupyter launcher tab, click on the "Desktop" tile.

![Desktop tab button in Jupyter launcher tab](./resources/desktop_tab.png)

After this, you should see a new tab open up in your browser window called "noVNC", with a basic desktop interface. Note if at first it doesn't connect, just close the tab and click the `D` tile a second time.
After this, you should see a new tab open up in your browser window called "Jupyter Remote Desktop Proxy", with a basic Linux desktop interface. Note if at first it doesn't connect, just close the tab and click the `D` tile a second time.

![Desktop interface shown in browser tab](./resources/desktop.png)

Expand Down
42 changes: 20 additions & 22 deletions napari-workshops/notebooks/spot_detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ nbscreenshot(viewer)

## Create an image filter

If you look carefull at the `spots` layer, you will notice that it contains background and
If you look carefully at the `spots` layer, you will notice that it contains background and
autofluorescence from the cells. It may help to just look at the single channel.

```{code-cell} ipython3
Expand All @@ -130,7 +130,8 @@ viewer.layers['nuclei'].visible = False
To improve spot detection, we will apply a high pass filter to improve the contrast of the spots.

A simple way to achieve this is to:
1. blur the image with a Gaussian, which removes high-frequency information—this is why we use it for denoising.
1. blur the image with a Gaussian, which removes high-frequency information (small features, including
our spots)—this is why we use it for denoising.
2. subtract the blurred image from the original.

Lets try this using the `gaussian_filter` from `scipy` with a sigma of 2 px and lets clip any negative values:
Expand Down Expand Up @@ -164,7 +165,7 @@ nbscreenshot(viewer)

## Detect spots

Next, we will use one of the blob detection algorithms from sci-kit image to
Next, we will use one of the blob detection algorithms from scikit-image to
perform the blob detection.

```{tip}
Expand All @@ -177,11 +178,9 @@ from skimage.feature import blob_log
# detect the spots on the filtered image
blobs_log = blob_log(
high_passed_spots,
max_sigma=3,
threshold=None, # use a relative threshold instead
threshold_rel=0.2
)
high_passed_spots, max_sigma=3,
threshold=None, # use a relative threshold instead
threshold_rel=0.2)
# convert the output of the blob detector to the
# desired points_coords and sizes arrays
Expand Down Expand Up @@ -216,21 +215,20 @@ viewer.camera.zoom = 8
nbscreenshot(viewer)
```

## Optional: using Points layer `properties`
## Optional: using Points layer `features`

`features` is a table associated with a Points layer that can store additional data associated with
a data point. It has one row per data element (Point) and one column per feature. This would enable you
to add other attributes like `volume` or `maximum-intensity` should you calculate those for each cell.
Importantly, napari can not only display the values of associated features in the status bar, but
also use them for styling, e.g. for `face_color`. For more information, see the
[Points layer guide](https://napari.org/stable/howtos/layers/points.html#using-the-points-features-table),
[the Points annotation tutorial](https://napari.org/stable/tutorials/annotation/annotate_points.html)
or the ["Add points with features" Gallery example](https://napari.org/stable/gallery/add_points_with_features.html#sphx-glr-gallery-add-points-with-features-py).

`properties` is a table associated with a Points layer that can store additional data associated with
a data point. It has one row per data element (Point) and one column per feature. Importantly,
napari can not only display the values of associated features in the status bar, but also use them for
styling, e.g. for `face_color`. For more information, see the [Points layer guide](https://napari.org/stable/howtos/layers/points.html#setting-point-edge-and-face-color-with-properties).

```{note}
napari plans to deprecate `properties` in favor of `features` in a future release, but for the time being
the documentation for `properties` is superior, so we use that here. Note that some examples in the Gallery
have been updated to use `features`, but for the purposes of these simple examples you can replace
`features` with `properties` or vice versa.
```

Let's use the `properties` dictionary to store the intensity value of the image at the coordinate of point
Let's use the `features` dictionary to store the intensity value of the image at the coordinate of point
and then we can encode the color of the point marker using that value.

First let's get an array of the pixel values of the original data array at the coordinates of our detected
Expand All @@ -242,10 +240,10 @@ tuple_of_spots_as_indexes = tuple(np.round(spot_coords).astype(int).T)
intensities = viewer.layers['spots'].data[tuple_of_spots_as_indexes]
```

Now we will set the `properties` table of our Points layer—we could have done this when we constructed the layer.
Now we will set the `features` table of our Points layer—we could have done this when we constructed the layer.

```{code-cell} ipython3
viewer.layers['spot_coords'].properties = {'intensity': intensities}
viewer.layers['spot_coords'].features = {'intensity': intensities}
```

Now when you mouseover a point, you should see the corresponding intensity value in the status bar.
Expand Down
40 changes: 30 additions & 10 deletions napari-workshops/notebooks/spot_detection_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ There are a number of ways to go about creating your own widgets, you can see [a

In this module, we will implement elements of our previous workflow as functions and then use [`magicgui.magicgui`](https://pyapp-kit.github.io/magicgui/api/magicgui/#magicguimagicgui) decorator on those functions to return us compound widgets that we can use to make exploring the parameters easier in the GUI. For a nice overview of the `magicgui` decorators, see [the official documentation](https://pyapp-kit.github.io/magicgui/decorators/).

## `binder` setup

```{code-cell} ipython3
:tags: [remove-output]
# this cell is required to run these notebooks on Binder. Make sure that you also have a desktop tab open.
import os
if 'BINDER_SERVICE_HOST' in os.environ:
os.environ['DISPLAY'] = ':1.0'
```

## Loading data

Let's get everything set up, based on the previous notebook:

```{code-cell} ipython3
Expand All @@ -45,6 +58,8 @@ viewer.add_image(nuclei, colormap = 'I Forest', blending = 'minimum')
viewer.add_image(spots, colormap = 'I Orange', blending='minimum')
```

## A basic filtering function

Now let's write a function that takes an array and a `sigma` value and performs the
high-pass operation.

Expand Down Expand Up @@ -96,7 +111,9 @@ For more information, see the official Python documentation for:
from magicgui import magicgui
@magicgui
def gaussian_high_pass(image: "napari.types.ImageData", sigma: float = 2)->"napari.types.ImageData":
def gaussian_high_pass(
image: "napari.types.ImageData", sigma: float = 2
) -> "napari.types.ImageData":
"""Apply a gaussian high pass filter to an image.
Parameters
Expand Down Expand Up @@ -194,10 +211,13 @@ viewer.window.remove_dock_widget("all")
```

```{code-cell} ipython3
@magicgui(auto_call=True,
sigma={"widget_type": "FloatSlider", "min": 0, "max": 20}
)
def gaussian_high_pass(image: "napari.types.ImageData", sigma: float = 2)->"napari.types.ImageData":
@magicgui(
auto_call=True,
sigma={"widget_type": "FloatSlider", "min": 0, "max": 20}
)
def gaussian_high_pass(
image: "napari.types.ImageData", sigma: float = 2
) -> "napari.types.ImageData":
"""Apply a gaussian high pass filter to an image.
Parameters
Expand Down Expand Up @@ -276,11 +296,11 @@ from skimage.feature import blob_log
@magicgui
def detect_spots(
image: "napari.layers.Image",
high_pass_sigma: float = 2,
spot_threshold: float = 0.2,
blob_sigma: float = 2
)->"napari.types.LayerDataTuple":
image: "napari.layers.Image",
high_pass_sigma: float = 2,
spot_threshold: float = 0.2,
blob_sigma: float = 2
) -> "napari.types.LayerDataTuple":
"""Apply a gaussian high pass filter to an image.
Parameters
Expand Down

0 comments on commit b6d9805

Please sign in to comment.