Source code for nwbwidgets.image

from os import path

import ipywidgets
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from ipywidgets import Layout, fixed, widgets
from pynwb import TimeSeries
from pynwb.image import GrayscaleImage, ImageSeries, RGBImage
from tifffile import TiffFile, imread

from .base import fig2widget
from .controllers import StartAndDurationController
from .utils.timeseries import (
    get_timeseries_maxt,
    get_timeseries_mint,
    timeseries_time_to_ind,
)


[docs]class ImageSeriesWidget(widgets.VBox): """Widget showing ImageSeries.""" SUPPORTED_EXTERNAL_FORMATS = (".tif", ".tiff") def __init__( self, imageseries: ImageSeries, foreign_time_window_controller: StartAndDurationController = None, **kwargs ): super().__init__() self.imageseries = imageseries self.controls = {} self.out_fig = None if imageseries.external_file and not path.exists(imageseries.external_file[0]): self.children = [ ipywidgets.HTML( f"Could not find associated external file " f"'{imageseries.external_file[0]}'.\nIf you are running this locally, make sure that the " f"external file is in the appropriate location. NWB Widgets does not" f" yet support streaming of external files on DANDI or S3." ) ] return if ( imageseries.external_file and path.splitext(imageseries.external_file[0])[1].lower() not in self.SUPPORTED_EXTERNAL_FORMATS ): self.children = [ ipywidgets.HTML( f"Could not open associated external file " f"'{imageseries.external_file[0]}'.\n Supported external formats: {self.SUPPORTED_EXTERNAL_FORMATS}" ) ] return # Set controller if foreign_time_window_controller is None: tmin = get_timeseries_mint(imageseries) if imageseries.external_file and imageseries.rate: tif = TiffFile(imageseries.external_file[0]) tmax = imageseries.starting_time + len(tif.pages) / imageseries.rate else: tmax = get_timeseries_maxt(imageseries) self.time_window_controller = StartAndDurationController(tmax, tmin) else: self.time_window_controller = foreign_time_window_controller self.set_controls(**kwargs) # Make widget figure self.set_out_fig() self.children = [self.out_fig, self.time_window_controller]
[docs] def time_to_index(self, time): if self.imageseries.external_file and self.imageseries.rate: return int((time - self.imageseries.starting_time) * self.imageseries.rate) else: return timeseries_time_to_ind(self.imageseries, time)
[docs] def set_controls(self, **kwargs): self.controls.update(timeseries=fixed(self.imageseries), time_window=self.time_window_controller) self.controls.update({key: widgets.fixed(val) for key, val in kwargs.items()})
[docs] def get_frame(self, idx): if self.imageseries.external_file is not None: return imread(self.imageseries.external_file, key=idx) else: return self.image_series.data[idx].T
[docs] def set_out_fig(self): self.out_fig = go.FigureWidget( data=go.Heatmap( z=self.get_frame(0), colorscale="gray", showscale=False, ) ) self.out_fig.update_layout( xaxis=go.layout.XAxis(showticklabels=False, ticks=""), yaxis=go.layout.YAxis(showticklabels=False, ticks="", scaleanchor="x", scaleratio=1), ) def on_change(change): # Read frame frame_number = self.time_to_index(change["new"][0]) image = self.get_frame(frame_number) self.out_fig.data[0].z = image self.controls["time_window"].observe(on_change)
[docs]def show_image_series(image_series: ImageSeries, neurodata_vis_spec: dict): if len(image_series.data.shape) == 3: return show_grayscale_image_series(image_series, neurodata_vis_spec) def show_image(index=0, mode="rgb"): fig, ax = plt.subplots(subplot_kw={"xticks": [], "yticks": []}) image = image_series.data[index] if mode == "bgr": image = image[:, :, ::-1] ax.imshow(image.transpose([1, 0, 2]), cmap="gray", aspect="auto") fig.show() return fig2widget(fig) slider = widgets.IntSlider( value=0, min=0, max=image_series.data.shape[0] - 1, orientation="horizontal", continuous_update=False, description="index", ) mode = widgets.Dropdown(options=("rgb", "bgr"), layout=Layout(width="200px"), description="mode") controls = {"index": slider, "mode": mode} out_fig = widgets.interactive_output(show_image, controls) vbox = widgets.VBox(children=[out_fig, slider, mode]) return vbox
[docs]def show_grayscale_image_series(image_series: ImageSeries, neurodata_vis_spec: dict): def show_image(index=0): fig, ax = plt.subplots(subplot_kw={"xticks": [], "yticks": []}) ax.imshow(image_series.data[index].T, cmap="gray", aspect="auto") return fig slider = widgets.IntSlider( value=0, min=0, max=image_series.data.shape[0] - 1, orientation="horizontal", continuous_update=False, description="index", ) controls = {"index": slider} out_fig = widgets.interactive_output(show_image, controls) vbox = widgets.VBox(children=[out_fig, slider]) return vbox
[docs]def show_index_series(index_series, neurodata_vis_spec: dict): show_timeseries = neurodata_vis_spec[TimeSeries] series_widget = show_timeseries(index_series) indexed_timeseries = index_series.indexed_timeseries image_series_widget = show_image_series(indexed_timeseries, neurodata_vis_spec) return widgets.VBox([series_widget, image_series_widget])
[docs]def show_grayscale_image(grayscale_image: GrayscaleImage, neurodata_vis_spec=None): fig, ax = plt.subplots() plt.imshow(grayscale_image.data[:].T, "gray") plt.axis("off") return fig
[docs]def show_rbga_image(rgb_image: RGBImage, neurodata_vis_spec=None): fig, ax = plt.subplots() plt.imshow(rgb_image.data[:].transpose([1, 0, 2])) plt.axis("off") return fig