Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lookup tables): Adding lookup table changes to explorers #147

Merged
merged 1 commit into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions pan3d/explorers/contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
vtkLoopSubdivisionFilter,
)
from vtkmodules.vtkFiltersCore import vtkAssignAttribute
from vtkmodules.vtkCommonCore import vtkLookupTable

# VTK factory initialization
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa
Expand All @@ -31,7 +32,7 @@
from trame.widgets import vuetify3 as v3, html

from pan3d.utils.convert import to_float, to_image
from pan3d.utils.presets import apply_preset, COLOR_PRESETS
from pan3d.utils.presets import set_preset, PRESETS

from pan3d.ui.vtk_view import Pan3DView
from pan3d.ui.css import base, preview
Expand Down Expand Up @@ -88,6 +89,8 @@ def __init__(self, server=None, local_rendering=None):
# -------------------------------------------------------------------------

def _setup_vtk(self):
self.lut = vtkLookupTable()

self.renderer = vtkRenderer(background=(0.8, 0.8, 0.8))
self.interactor = vtkRenderWindowInteractor()
self.render_window = vtkRenderWindow(off_screen_rendering=1)
Expand Down Expand Up @@ -118,6 +121,7 @@ def _setup_vtk(self):
input_connection=self.bands.output_port,
scalar_visibility=1,
interpolate_scalars_before_mapping=1,
lookup_table=self.lut,
)
self.mapper.SelectColorArray("scalars")
self.mapper.SetScalarModeToUsePointFieldData()
Expand Down Expand Up @@ -366,7 +370,7 @@ def _build_ui(self, **kwargs):
placeholder="Color Preset",
prepend_inner_icon="mdi-palette",
v_model=("color_preset", "Cool to Warm"),
items=("color_presets", COLOR_PRESETS),
items=("color_presets", list(PRESETS.keys())),
hide_details=True,
density="compact",
flat=True,
Expand Down Expand Up @@ -463,8 +467,8 @@ def _on_update_color_range(
):
if self.last_preset != color_preset:
self.last_preset = color_preset
apply_preset(self.actor, [color_min, color_max], color_preset)
self.state.preset_img = to_image(self.actor.mapper.lookup_table, 255)
set_preset(self.lut, color_preset)
self.state.preset_img = to_image(self.lut, 255)

self.mapper.SetScalarRange(color_min, color_max)
self.bands.GenerateValues(nb_contours, [color_min, color_max])
Expand Down
18 changes: 13 additions & 5 deletions pan3d/explorers/globe.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from vtkmodules.vtkFiltersGeometry import vtkDataSetSurfaceFilter
from vtkmodules.vtkInteractionWidgets import vtkOrientationMarkerWidget
from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
from vtkmodules.vtkCommonCore import vtkLookupTable

import json
import traceback
Expand All @@ -25,7 +26,7 @@
from pan3d.xarray.algorithm import vtkXArrayRectilinearSource

from pan3d.utils.convert import update_camera, to_image, to_float
from pan3d.utils.presets import apply_preset
from pan3d.utils.presets import set_preset

from pan3d.ui.vtk_view import Pan3DView, Pan3DScalarBar
from pan3d.ui.preview import SummaryToolbar, ControlPanel
Expand Down Expand Up @@ -135,6 +136,8 @@ def _setup_vtk(self):
get_continent_outlines,
)

self.lut = vtkLookupTable()

self.globe = get_globe()
self.texture = get_globe_texture()
self.gmapper = vtkPolyDataMapper(input_data_object=self.globe)
Expand All @@ -156,7 +159,9 @@ def _setup_vtk(self):
input_connection=self.dglobe.output_port
)

self.mapper = vtkPolyDataMapper(input_connection=self.geometry.output_port)
self.mapper = vtkPolyDataMapper(
input_connection=self.geometry.output_port, lookup_table=self.lut
)
self.actor = vtkActor(mapper=self.mapper, visibility=0)

self.interactor.Initialize()
Expand Down Expand Up @@ -306,10 +311,13 @@ def _on_color_preset(
):
color_min = float(color_min)
color_max = float(color_max)
color = nan_colors[nan_color]
self.mapper.SetScalarRange(color_min, color_max)
apply_preset(self.actor, [color_min, color_max], color_preset, color)
self.state.preset_img = to_image(self.actor.mapper.lookup_table, 255)

set_preset(self.lut, color_preset)
self.state.preset_img = to_image(self.lut, 255)

color = nan_colors[nan_color]
self.lut.SetNanColor(color)

self.ctrl.view_update()

Expand Down
28 changes: 19 additions & 9 deletions pan3d/explorers/slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import json
from pathlib import Path

from vtkmodules.vtkCommonCore import vtkLookupTable

from vtkmodules.vtkRenderingCore import (
vtkRenderer,
vtkRenderWindowInteractor,
Expand All @@ -11,6 +13,7 @@
vtkPolyDataMapper,
vtkTextProperty,
)

from vtkmodules.vtkRenderingAnnotation import (
vtkScalarBarActor,
)
Expand Down Expand Up @@ -38,7 +41,7 @@

from pan3d.ui.vtk_view import Pan3DView
from pan3d.ui.common import NumericField
from pan3d.utils.presets import update_preset, use_preset, COLOR_PRESETS
from pan3d.utils.presets import set_preset, PRESETS


@TrameApp()
Expand Down Expand Up @@ -113,6 +116,9 @@ def _setup_vtk(self, source=None, import_state=None):

color_range = ds.point_data[self.state.color_by].GetRange()

# Create lookup table
self.lut = vtkLookupTable()

# Build rendering pipeline
self.renderer = vtkRenderer()
self.interactor = vtkRenderWindowInteractor()
Expand All @@ -125,7 +131,7 @@ def _setup_vtk(self, source=None, import_state=None):
cutter.SetCutFunction(plane)
cutter.input_connection = self.source.output_port
slice_actor = vtkActor()
slice_mapper = vtkDataSetMapper()
slice_mapper = vtkDataSetMapper(lookup_table=self.lut)
slice_mapper.SetInputConnection(cutter.GetOutputPort())
slice_mapper.SetScalarRange(*color_range)
slice_mapper.SelectColorArray(self.state.color_by)
Expand All @@ -139,7 +145,7 @@ def _setup_vtk(self, source=None, import_state=None):

outline = vtkOutlineFilter()
outline_actor = vtkActor()
outline_mapper = vtkPolyDataMapper()
outline_mapper = vtkPolyDataMapper(lookup_table=self.lut)
outline.input_connection = self.source.output_port
outline_mapper.SetInputConnection(outline.GetOutputPort())
outline_actor.SetMapper(outline_mapper)
Expand All @@ -149,7 +155,7 @@ def _setup_vtk(self, source=None, import_state=None):
self.outline_mapper = outline_mapper

data_actor = vtkActor()
data_mapper = vtkDataSetMapper()
data_mapper = vtkDataSetMapper(lookup_table=self.lut)
data_mapper.input_connection = self.source.output_port
data_mapper.SetScalarRange(*color_range)
data_actor.SetMapper(data_mapper)
Expand All @@ -159,7 +165,7 @@ def _setup_vtk(self, source=None, import_state=None):
self.data_mapper = data_mapper

sbar_actor = vtkScalarBarActor()
sbar_actor.SetLookupTable(self.slice_mapper.GetLookupTable())
sbar_actor.SetLookupTable(self.lut)
sbar_actor.SetMaximumHeightInPixels(600)
sbar_actor.SetMaximumWidthInPixels(100)
sbar_actor.SetTitleRatio(0.2)
Expand Down Expand Up @@ -294,15 +300,19 @@ def _on_colormap_change(self, cmap, **_):
Performs all the steps necessary to visualize correct data when the
color map is updated
"""
use_preset(self.slice_actor, self.data_actor, self.sbar_actor, cmap)
set_preset(self.lut, cmap)
self.ctrl.view_update()

@change("logscale")
def _on_log_scale_change(self, logscale, **_):
"""
Performs all the steps necessary when user toggles log scale for color map
"""
update_preset(self.slice_actor, self.sbar_actor, logscale)
if logscale:
self.lut.SetScaleToLog10()
else:
self.lut.SetScaleToLinear()

self.ctrl.view_update()

def _set_view_2D(self, axis):
Expand Down Expand Up @@ -660,8 +670,8 @@ def _build_ui(self, *args, **kwargs):
)
v3.VSelect(
label="Preset",
v_model=("cmap", COLOR_PRESETS[0]),
items=("colormaps", COLOR_PRESETS),
v_model=("cmap", "Fast"),
items=("colormaps", list(PRESETS.keys())),
outlined=True,
**style,
)
Expand Down
106 changes: 1 addition & 105 deletions pan3d/utils/presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from pathlib import Path
import numpy as np

from vtkmodules.vtkRenderingCore import vtkColorTransferFunction, vtkActor
from vtkmodules.vtkRenderingCore import vtkColorTransferFunction
from vtkmodules.vtkCommonCore import vtkLookupTable

PRESETS = {
Expand Down Expand Up @@ -75,107 +75,3 @@ def set_preset(lut: vtkLookupTable, preset_name: str, n_colors=255):
rgb = colors.GetColor(x)
lut.SetTableValue(i, *rgb)
lut.Build()


# --------------------------------------------------------

hsv_colors = {
"Greyscale": {
"Hue": (0.0, 0.0),
"Saturation": (0.0, 0.0),
"Range": (0.0, 1.0),
},
"Inv Greyscale": {
"Hue": (0.0, 0.666),
"Saturation": (0.0, 0.0),
"Range": (1.0, 0.0),
},
}

rgb_colors = {}
try:
data = json.loads(Path(__file__).with_name("presets.json").read_text())
for cmap in data:
name = cmap["Name"]
srgb = np.array(cmap["RGBPoints"])
tfunc = vtkColorTransferFunction()
for arr in np.split(srgb, len(srgb) / 4):
tfunc.AddRGBPoint(arr[0], arr[1], arr[2], arr[3])
info = {"TF": tfunc, "Range": (srgb[0], srgb[-4])}
rgb_colors[name] = info
except Exception as e:
print("Error loading diverging color maps : ", e)


def convert_tfunc_to_lut(tfunc: vtkColorTransferFunction, tfrange):
lut = vtkLookupTable()
lut.SetNumberOfTableValues(256)
tflen = tfrange[1] - tfrange[0]
for i in range(256):
t = tfrange[0] + tflen * i / 255
rgb = list(tfunc.GetColor(t))
lut.SetTableValue(i, rgb[0], rgb[1], rgb[2])
lut.Build()
return lut


def apply_preset(actor: vtkActor, srange, preset: str, nan_color=[0, 0, 0, 0]) -> None:
if preset in list(hsv_colors.keys()):
lut = vtkLookupTable()
lut.SetNumberOfTableValues(256)
mapper = actor.GetMapper()
mapper.SetLookupTable(lut)
preset = hsv_colors[preset]
hue = preset["Hue"]
sat = preset["Saturation"]
rng = preset["Range"]
lut.SetHueRange(hue[0], hue[1])
lut.SetSaturationRange(sat[0], sat[1])
lut.SetValueRange(rng[0], rng[1])
lut.SetNanColor(nan_color)
lut.Build()
elif preset in list(rgb_colors.keys()):
info = rgb_colors[preset]
tfunc = info["TF"]
tfrange = info["Range"]
lut = convert_tfunc_to_lut(tfunc, tfrange)
lut.SetNanColor(nan_color)
mapper = actor.GetMapper()
mapper.SetLookupTable(lut)
mapper.SetScalarRange(srange[0], srange[1])


def use_preset(sactor: vtkActor, dactor: vtkActor, sbar: vtkActor, preset: str) -> None:
"""
Given the slice, data, and scalar bar actor, applies the provided preset
and updates the actors and the scalar bar
"""
srange = sactor.GetMapper().GetScalarRange()
drange = dactor.GetMapper().GetScalarRange()
actors = [sactor, dactor]
ranges = [srange, drange]
for actor, range in zip(actors, ranges):
apply_preset(actor, range, preset)
sactor.GetMapper().SetScalarRange(srange[0], srange[1])
dactor.GetMapper().SetScalarRange(drange[0], drange[1])
sbar.SetLookupTable(sactor.GetMapper().GetLookupTable())


def update_preset(actor: vtkActor, sbar: vtkActor, logcale: bool) -> None:
"""
Given an actor, scalar bar, and the option for whether to use log scale,
make changes to the lookup table for the actor, and update the scalar bar
"""
lut = actor.GetMapper().GetLookupTable()
if logcale:
lut.SetScaleToLog10()
else:
lut.SetScaleToLinear()
lut.Build()
sbar.SetLookupTable(lut)


COLOR_PRESETS = [
*list(hsv_colors.keys()),
*list(rgb_colors.keys()),
]
Loading