Skip to content

Commit

Permalink
covering grid support in viewer module
Browse files Browse the repository at this point in the history
  • Loading branch information
chrishavlin committed Apr 2, 2024
1 parent 93aa66e commit 79e24f7
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 36 deletions.
132 changes: 108 additions & 24 deletions docs/examples/ytnapari_scene_01_intro.ipynb

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions src/yt_napari/_gui_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,16 @@ def get_widget_instance(self, pydantic_model, field: str):
func, args, kwargs = self.registry[pydantic_model][field]["magicgui"]
return func(*args, **kwargs)

def get_pydantic_attr(self, pydantic_model, field: str, widget_instance):
def get_pydantic_attr(
self, pydantic_model, field: str, widget_instance, required: bool = True
):
# given a widget instance, return an object that can be used to set a
# pydantic field
if self.is_registered(pydantic_model, field, required=True):
if self.is_registered(pydantic_model, field, required=required):
func, args, kwargs = self.registry[pydantic_model][field]["pydantic"]
return func(widget_instance, *args, **kwargs)
else:
raise RuntimeError("unexpected")
raise RuntimeError("Could not retrieve pydantic attribute.")

def add_pydantic_to_container(
self,
Expand Down
25 changes: 16 additions & 9 deletions src/yt_napari/_model_ingestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ def _le_re_to_cen_wid(
return center, width


def _get_covering_grid(
ds, left_edge, right_edge, level, num_ghost_zones, test_dims=None
):
# returns a covering grid instance and the resolution of the covering grid
if test_dims is None:
test_dims = (4, 4, 4)
nghostzones = num_ghost_zones
temp_cg = ds.covering_grid(level, left_edge, test_dims, num_ghost_zones=nghostzones)
effective_dds = temp_cg.dds
dims = (right_edge - left_edge) / effective_dds
# get the actual covering grid
frb = ds.covering_grid(level, left_edge, dims, num_ghost_zones=nghostzones)
return frb, dims


class LayerDomain:
# container for domain info for a single layer
# left_edge, right_edge, resolution, n_d are all self explanatory.
Expand Down Expand Up @@ -462,15 +477,7 @@ def _load_3D_regions(
LE[2] : RE[2] : complex(0, res[2]), # noqa: E203
]
elif isinstance(sel, CoveringGrid):
# get a temp covering grid with specified ghost zones then
# recalcuate dims at correct dds
dims = (4, 4, 4)
nghostzones = sel.num_ghost_zones
temp_cg = ds.covering_grid(sel.level, LE, dims, num_ghost_zones=nghostzones)
effective_dds = temp_cg.dds
dims = (RE - LE) / effective_dds
# get the actual covering grid
frb = ds.covering_grid(sel.level, LE, dims, num_ghost_zones=nghostzones)
frb, dims = _get_covering_grid(ds, LE, RE, sel.level, sel.num_ghost_zones)
res = dims

layer_domain = LayerDomain(left_edge=LE, right_edge=RE, resolution=res)
Expand Down
4 changes: 4 additions & 0 deletions src/yt_napari/_tests/test_gui_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ def get_value_from_nested(container_widget, extra_string):
pyvalue = reg.get_pydantic_attr(Model, "field_1", widget_instance)
assert pyvalue == "2_testxyz"

with pytest.raises(RuntimeError, match="Could not retrieve pydantic attribute."):
reg.get_pydantic_attr(
Model, "field_does_not_exist", widget_instance, required=False
)
widget_instance.close()


Expand Down
7 changes: 7 additions & 0 deletions src/yt_napari/_tests/test_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ def test_viewer(make_napari_viewer, yt_ds, caplog):
expected_layers += 1
assert len(viewer.layers) == expected_layers

LE = yt_ds.domain_left_edge
dds = yt_ds.domain_width / yt_ds.domain_dimensions
RE = yt_ds.arr(LE + dds * 10)
sc.add_covering_grid(viewer, yt_ds, ("gas", "density"), left_edge=LE, right_edge=RE)
expected_layers += 1
assert len(viewer.layers) == expected_layers

# build a new scene so it builds from prior
sc = Scene()
sc.add_region(viewer, yt_ds, ("gas", "density"))
Expand Down
90 changes: 90 additions & 0 deletions src/yt_napari/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,96 @@ def add_region(
**kwargs,
)

def add_covering_grid(
self,
viewer: Viewer,
ds,
field: Tuple[str, str],
left_edge: Optional[unyt_array] = None,
right_edge: Optional[unyt_array] = None,
level: Optional[int] = 0,
num_ghost_zones: Optional[int] = 0,
take_log: Optional[bool] = None,
colormap: Optional[str] = None,
link_to: Optional[Union[str, Layer]] = None,
rescale: Optional[bool] = False,
**kwargs,
):
"""
uniformly sample a region from a yt dataset using a covering grid
and add it to a viewer
Parameters
----------
viewer: napari.Viewer
the active napari viewer
ds
the yt dataset to sample
field: Tuple[str, str]
the field tuple to sample e.g., ('enzo', 'Density')
left_edge: unyt_array
the left edge of the bounding box
right_edge: unyt_array
the right edge of the bounding box
level: int
the level to sample at (default 0)
num_ghost_zones: int
number of ghost zones to inclue (default 0)
take_log : Optional[bool]
if True, will take the log of the extracted data. Defaults to the
default behavior for the field set by ds.
colormap : Optional[str]
the color map to use, default is "viridis"
link_to : Optional[Union[str, Layer]]
specify a layer to which the new layer should link
**kwargs :
any keyword argument accepted by Viewer.add_image()
Examples
--------
>>> import napari
>>> import yt
>>> from yt_napari.viewer import Scene
>>> viewer = napari.Viewer()
>>> ds = yt.load_sample("IsolatedGalaxy")
>>> yt_scene = Scene()
>>> yt_scene.add_region(viewer, ds, ("enzo", "Temperature"))
"""

# set defaults
if left_edge is None:
left_edge = ds.domain_left_edge

Check warning on line 263 in src/yt_napari/viewer.py

View check run for this annotation

Codecov / codecov/patch

src/yt_napari/viewer.py#L263

Added line #L263 was not covered by tests
if right_edge is None:
right_edge = ds.domain_right_edge

Check warning on line 265 in src/yt_napari/viewer.py

View check run for this annotation

Codecov / codecov/patch

src/yt_napari/viewer.py#L265

Added line #L265 was not covered by tests

if take_log is None:
take_log = ds._get_field_info(field).take_log

# create the fixed resolution buffer
frb, dims = _mi._get_covering_grid(
ds, left_edge, right_edge, level, num_ghost_zones
)
data = frb[field]
if take_log:
data = np.log10(data)

# add the bounds of this new layer
layer_domain = _mi.LayerDomain(left_edge, right_edge, dims)

self._add_to_scene(
viewer,
data,
layer_domain,
field,
take_log,
colormap=colormap,
link_to=link_to,
rescale=rescale,
**kwargs,
)

def add_to_viewer(
self,
viewer: Viewer,
Expand Down

0 comments on commit 79e24f7

Please sign in to comment.