-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathviewer_state.py
90 lines (76 loc) · 2.77 KB
/
viewer_state.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from dataclasses import dataclass
import napari
import numpy as np
@dataclass(frozen=True)
class ViewerState:
"""The state of the viewer camera, dims, and layers.
Parameters
----------
camera : dict
The state of the `napari.components.Camera` in the viewer.
dims : dict
The state of the `napari.components.Dims` in the viewer.
layers : dict
A map of layer.name -> Dict[k, v] for layer attributes for each layer in the viewer
(excluding metadata).
"""
camera: dict
dims: dict
layers: dict
@classmethod
def from_viewer(cls, viewer: napari.viewer.Viewer):
"""Create a ViewerState from a viewer instance."""
layers = {
layer.name: layer.as_layer_data_tuple()[1]
for layer in viewer.layers
}
for layer_attributes in layers.values():
layer_attributes.pop("metadata")
layer_attributes.pop("properties", None)
return cls(
camera=viewer.camera.dict(), dims=viewer.dims.dict(), layers=layers
)
def apply(self, viewer: napari.viewer.Viewer):
"""Update `viewer` to match this ViewerState.
Parameters
----------
viewer : napari.viewer.Viewer
A napari viewer. (viewer state will be directly modified)
"""
viewer.camera.update(self.camera)
viewer.dims.update(self.dims)
for layer_name, layer_state in self.layers.items():
layer = viewer.layers[layer_name]
layer_attributes = layer.as_layer_data_tuple()[1]
for attribute_name, value in layer_state.items():
original_value = layer_attributes[attribute_name]
# Only set if value differs to avoid expensive redraws
if not np.array_equal(original_value, value):
setattr(layer, attribute_name, value)
def render(
self, viewer: napari.viewer.Viewer, canvas_only: bool = True
) -> np.ndarray:
"""Render this ViewerState to an image.
Parameters
----------
viewer : napari.viewer.Viewer
A napari viewer to render screenshots from.
canvas_only : bool, optional
Whether to include only the canvas (and exclude the napari
gui), by default True
Returns
-------
np.ndarray
An RGBA image of shape (h, w, 4).
"""
self.apply(viewer)
return viewer.screenshot(canvas_only=canvas_only, flash=False)
def __eq__(self, other):
if isinstance(other, ViewerState):
return (
self.camera == other.camera
and self.dims == other.dims
and self.layers == other.layers
)
else:
return False