Skip to content

Commit

Permalink
Merge pull request #13 from Carifio24/aspect-and-clipping
Browse files Browse the repository at this point in the history
Support non-native aspect ratio and clip data to bounds
  • Loading branch information
Carifio24 authored Dec 26, 2023
2 parents 983604d + fd05288 commit 878706a
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 42 deletions.
28 changes: 14 additions & 14 deletions glue_ar/export_dialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
<string>Export 3D Volume</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QLabel" name="label_settings_message">
<property name="text">
<string>Set the export settings for each layer</string>
</property>
</widget>
<item row="3" column="0">
<widget class="QListWidget" name="listsel_layer"/>
</item>
<item row="4" column="0">
<layout class="QFormLayout" name="layer_layout"/>
</item>
<item row="5" column="0">
<widget class="QWidget" name="widget" native="true">
Expand Down Expand Up @@ -60,21 +59,22 @@
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="combosel_filetype"/>
</item>
<item row="3" column="0">
<widget class="QListWidget" name="listsel_layer"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_filetype_message">
<property name="text">
<string>Select the export filetype</string>
</property>
</widget>
</item>
<item row="4" column="0">
<layout class="QFormLayout" name="layer_layout"/>
<item row="1" column="0">
<widget class="QComboBox" name="combosel_filetype"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_settings_message">
<property name="text">
<string>Set the export settings for each layer</string>
</property>
</widget>
</item>
</layout>
</widget>
Expand Down
22 changes: 15 additions & 7 deletions glue_ar/scatter.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from math import floor

import pyvista as pv
from glue_ar.utils import layer_color, xyz_bounds, xyz_for_layer

Expand All @@ -6,7 +8,7 @@
def scatter_layer_as_points(viewer_state, layer_state):
xyz = xyz_for_layer(viewer_state, layer_state)
return {
"data": xyz,
"mesh": xyz,
"color": layer_color(layer_state),
"opacity": layer_state.alpha,
"style": "points_gaussian",
Expand All @@ -18,7 +20,7 @@ def scatter_layer_as_points(viewer_state, layer_state):
def scatter_layer_as_spheres(viewer_state, layer_state):
data = xyz_for_layer(viewer_state, layer_state)
return {
"data": [pv.Sphere(center=p) for p in data]
"mesh": [pv.Sphere(center=p) for p in data]
}


Expand All @@ -27,7 +29,7 @@ def scatter_layer_as_glyphs(viewer_state, layer_state, glyph):
points = pv.PointSet(data)
glyphs = points.glyph(geom=glyph, orient=False, scale=False)
return {
"data": glyphs,
"mesh": glyphs,
"color": layer_color(layer_state),
"opacity": layer_state.alpha,
}
Expand All @@ -36,16 +38,21 @@ def scatter_layer_as_glyphs(viewer_state, layer_state, glyph):
def scatter_layer_as_multiblock(viewer_state, layer_state,
theta_resolution=8,
phi_resolution=8,
scaled=True):
data = xyz_for_layer(viewer_state, layer_state, scaled=scaled)
scaled=True,
clip_to_bounds=True):
data = xyz_for_layer(viewer_state, layer_state,
preserve_aspect=viewer_state.native_aspect,
clip_to_bounds=clip_to_bounds,
scaled=scaled)
bounds = xyz_bounds(viewer_state)
factor = max((abs(b[1] - b[0]) for b in bounds))
radius = layer_state.size_scaling * layer_state.size / factor
radius = (layer_state.size_scaling * layer_state.size) / factor
spheres = [pv.Sphere(center=p, radius=radius, phi_resolution=phi_resolution, theta_resolution=theta_resolution) for p in data]
blocks = pv.MultiBlock(spheres)
geometry = blocks.extract_geometry()

info = {
"data": geometry,
"mesh": geometry,
"opacity": layer_state.alpha
}
if layer_state.color_mode == "Fixed":
Expand All @@ -66,4 +73,5 @@ def scatter_layer_as_multiblock(viewer_state, layer_state,
info["cmap"] = cmap
info["clim"] = clim
info["scalars"] = "colors"

return info
26 changes: 19 additions & 7 deletions glue_ar/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from glue_ar.scatter import scatter_layer_as_multiblock
from glue_ar.export import export_gl, export_modelviewer
from glue_ar.utils import bounds_3d_from_layers
from glue_ar.volume import bounds_3d, meshes_for_volume_layer

__all__ = ["GLScatterExportTool", "GLVolumeExportTool"]
Expand Down Expand Up @@ -45,9 +46,13 @@ def activate(self):
layer_states = [layer.state for layer in self.viewer.layers if layer.enabled and layer.state.visible]
for layer_state in layer_states:
layer_info = dialog.state_dictionary[layer_state.layer.label].as_dict()
mesh_info = scatter_layer_as_multiblock(self.viewer.state, layer_state, **layer_info, scaled=True)
data = mesh_info.pop("data")
plotter.add_mesh(data, **mesh_info)
mesh_info = scatter_layer_as_multiblock(self.viewer.state, layer_state,
scaled=True,
clip_to_bounds=self.viewer.state.clip_data,
**layer_info)
mesh = mesh_info.pop("mesh")
if len(mesh.points) > 0:
plotter.add_mesh(mesh, **mesh_info)

dir, base = split(export_path)
name, ext = splitext(base)
Expand Down Expand Up @@ -79,8 +84,11 @@ def activate(self):

plotter = pv.Plotter()
layer_states = [layer.state for layer in self.viewer.layers if layer.enabled and layer.state.visible]
bounds = bounds_3d(self.viewer.state)
frbs = {}
if self.viewer.state.clip_data:
bounds = bounds_3d(self.viewer.state)
else:
bounds = bounds_3d_from_layers(self.viewer.state, layer_states)
for layer_state in layer_states:
layer_info = dialog.state_dictionary[layer_state.layer.label].as_dict()
if isinstance(layer_state, VolumeLayerState):
Expand All @@ -89,9 +97,13 @@ def activate(self):
precomputed_frbs=frbs,
**layer_info)
else:
mesh_info = scatter_layer_as_multiblock(self.viewer.state, layer_state, **layer_info, scaled=False)
data = mesh_info.pop("data")
plotter.add_mesh(data, **mesh_info)
mesh_info = scatter_layer_as_multiblock(self.viewer.state, layer_state,
scaled=False,
clip_to_bounds=self.viewer.state.clip_data,
**layer_info)
mesh = mesh_info.pop("mesh")
if len(mesh.points) > 0:
plotter.add_mesh(mesh, **mesh_info)

dir, base = split(export_path)
name, ext = splitext(base)
Expand Down
45 changes: 36 additions & 9 deletions glue_ar/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from glue.core.subset_group import GroupedSubset
from numpy import array
from numpy import array, inf


def isomin_for_layer(viewer_state, layer):
Expand All @@ -17,6 +17,18 @@ def xyz_bounds(viewer_state):
(viewer_state.z_min, viewer_state.z_max)]


def bounds_3d_from_layers(viewer_state, layer_states):
mins = [inf, inf, inf]
maxes = [-inf, -inf, -inf]
atts = viewer_state.x_att, viewer_state.y_att, viewer_state.z_att
for state in layer_states:
data = state.layer.layer
mins = [min(min(data[att]), m) for m, att in zip(mins, atts)]
maxes = [max(max(data[att]), m) for m, att in zip(maxes, atts)]
print(mins)
return [(l, u) for l, u in zip(mins, maxes)]


# TODO: Make this better?
# glue-plotly has had to deal with similar issues,
# the utilities there are at least better than this
Expand All @@ -27,8 +39,6 @@ def layer_color(layer_state):
return layer_color


# data should be list of numpy arrays
# Think about being more format-agnostic later
def scale(data, bounds, preserve_aspect=True):
if preserve_aspect:
ranges = [abs(bds[1] - bds[0]) for bds in bounds]
Expand All @@ -37,25 +47,42 @@ def scale(data, bounds, preserve_aspect=True):
bds = bounds[index]
m = 2 / (bds[1] - bds[0])
b = (bds[0] + bds[1]) / (bds[1] - bds[0])
return [m * d + b for d in data]
scaled = [[m * v + b for v in d] for d in data]
else:
scaled = []
for idx, bds in enumerate(bounds):
m = 2 / (bds[1] - bds[0])
b = (bds[0] + bds[1]) / (bds[1] - bds[0])
scaled.append(m * data[idx] + b)
return scaled
scaled.append([m * d + b for d in data[idx]])

return scaled


# TODO: Worry about efficiency later
def xyz_for_layer(viewer_state, layer_state, scaled=False, preserve_aspect=True):
# and just generally make this better
def xyz_for_layer(viewer_state, layer_state,
scaled=False,
preserve_aspect=True,
clip_to_bounds=True):
xs = layer_state.layer[viewer_state.x_att]
ys = layer_state.layer[viewer_state.y_att]
zs = layer_state.layer[viewer_state.z_att]
vals = [xs, ys, zs]

if scaled:
if scaled or clip_to_bounds:
bounds = xyz_bounds(viewer_state)
vals = scale(vals, bounds, preserve_aspect=preserve_aspect)
if clip_to_bounds:
xs, ys, zs = [], [], []
for x, y, z in zip(*vals):
if (x >= bounds[0][0] and x <= bounds[0][1]) and \
(y >= bounds[1][0] and y <= bounds[1][1]) and \
(z >= bounds[2][0] and z <= bounds[2][1]):
xs.append(x)
ys.append(y)
zs.append(z)
vals = [xs, ys, zs]

if scaled:
vals = scale(vals, bounds, preserve_aspect=preserve_aspect)

return array(list(zip(*vals)))
9 changes: 4 additions & 5 deletions glue_ar/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@ def meshes_for_volume_layer(viewer_state, layer_state, bounds,
use_gaussian_filter=False, smoothing_iterations=0,
precomputed_frbs=None):

precomputed_frbs = precomputed_frbs or {}

layer_content = layer_state.layer
parent = layer_content.data if isinstance(layer_content, GroupedSubset) else layer_content

parent_label = parent.label
if parent_label in precomputed_frbs:
if precomputed_frbs is not None and parent_label in precomputed_frbs:
data = precomputed_frbs[parent_label]
else:
data = parent.compute_fixed_resolution_buffer(
target_data=viewer_state.reference_data,
bounds=bounds,
target_cid=layer_state.attribute)
precomputed_frbs[parent_label] = data
if precomputed_frbs is not None:
precomputed_frbs[parent_label] = data

if isinstance(layer_state.layer, GroupedSubset):
subcube = parent.compute_fixed_resolution_buffer(
Expand Down Expand Up @@ -60,7 +59,7 @@ def meshes_for_volume_layer(viewer_state, layer_state, bounds,
isodata = isodata.smooth(n_iter=int(smoothing_iterations))

return {
"data": isodata,
"mesh": isodata,
"color": layer_color(layer_state),
"opacity": layer_state.alpha,
# "isomin": isomin,
Expand Down

0 comments on commit 878706a

Please sign in to comment.