Skip to content

Commit

Permalink
changed main file for sync view and changed show_details file for box…
Browse files Browse the repository at this point in the history
… select option
  • Loading branch information
BanikSampad committed Nov 13, 2024
1 parent 80c5ce9 commit cce60ca
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 98 deletions.
218 changes: 140 additions & 78 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,90 +4,152 @@
import base64
import json
import panel as pn
from openvisuspy import SetupLogger, Slice, ProbeTool, cbool
import time

from openvisuspy import SetupLogger, Slice, ProbeTool,cbool
# Global synchronization lock and throttle variables
sync_in_progress = False
last_sync_time = 0
throttle_delay = 0.1 # Throttle delay in seconds

# ////////////////////////////////////////////////////////////////////////////
def SyncSlices(slice1, slice2, box1=None, box2=None):

if box1 is None:
box1=slice1.db.getPhysicBox()

if box2 is None:
box2=slice2.db.getPhysicBox()

# map box1 to box2
(a, b), (c, d)=box1
(A, B), (C, D)=box2
def throttle(func, *args, **kwargs):
"""Throttle function calls to limit frequency."""
global last_sync_time
current_time = time.time()
if current_time - last_sync_time >= throttle_delay:
last_sync_time = current_time
func(*args, **kwargs)

x, y, w, h = slice1.canvas.getViewport()
x1, x2 = [A + ((value - a) / (b - a)) * (B - A) for value in [x, x + w]]
y1, y2 = [C + ((value - c) / (d - c)) * (D - C) for value in [y, y + h]]
slice2.canvas.setViewport([x1, y1, x2 - x1, y2 - y1])
slice2.refresh("SyncSlices")
def SyncSlices(slice1, slice2, box1=None, box2=None):
"""Synchronize from slice1 (original) to slice2 (super-resolution)"""
global sync_in_progress
if sync_in_progress:
return # Prevent re-entrant synchronization

sync_in_progress = True
try:
if box1 is None:
box1 = slice1.db.getPhysicBox()
if box2 is None:
box2 = slice2.db.getPhysicBox()

# Map box1 to box2
(a, b), (c, d) = box1
(A, B), (C, D) = box2

x, y, w, h = slice1.canvas.getViewport()

x1, x2 = [A + ((value - a) / (b - a)) * (B - A) for value in [x, x + w]]
y1, y2 = [C + ((value - c) / (d - c)) * (D - C) for value in [y, y + h]]
slice2.canvas.setViewport([x1, y1, x2 - x1, y2 - y1])
slice2.refresh("SyncSlices")
finally:
sync_in_progress = False

def SyncSlicesReverse(slice2, slice1, box1=None, box2=None):
"""Synchronize from slice2 (super-resolution) to slice1 (original)"""
global sync_in_progress
if sync_in_progress:
return # Prevent re-entrant synchronization

sync_in_progress = True
try:
if box1 is None:
box1 = slice1.db.getPhysicBox()
if box2 is None:
box2 = slice2.db.getPhysicBox()

# Map box2 to box1
(A, B), (C, D) = box2
(a, b), (c, d) = box1

x, y, w, h = slice2.canvas.getViewport()

x1, x2 = [a + ((value - A) / (B - A)) * (b - a) for value in [x, x + w]]
y1, y2 = [c + ((value - C) / (D - C)) * (d - c) for value in [y, y + h]]
slice1.canvas.setViewport([x1, y1, x2 - x1, y2 - y1])
slice1.refresh("SyncSlicesReverse")
finally:
sync_in_progress = False

# ////////////////////////////////////////////////////////////////////////////
if __name__.startswith('bokeh'):

pn.extension(
"ipywidgets",
"floatpanel",
"codeeditor",
log_level="DEBUG",
notifications=True,
sizing_mode="stretch_width"
)

query_params = {k: v for k,v in pn.state.location.query_params.items()}

log_filename = os.environ.get("OPENVISUSPY_DASHBOARDS_LOG_FILENAME", "/tmp/openvisuspy-dashboards.log")
logger = SetupLogger(log_filename=log_filename, logging_level=logging.DEBUG)

# sync view
if len(sys.argv[1:])==2:

from openvisuspy.utils import SafeCallback
from panel import Column, Row

slice1 = Slice();slice1.load(sys.argv[1])
slice2 = Slice();slice2.load(sys.argv[2])

show_options = {
"top": [
[
"palette",
"color_mapper_type",
"resolution",
"num_refinements",
"field",
"range_mode",
"range_min",
"range_max"
],
],
# "bottom": [["request", "response"]],
}
slice1.setShowOptions(show_options)
slice2.setShowOptions(show_options)
slice1.scene_body.param.watch( SafeCallback(lambda evt: SyncSlices(slice1,slice2)), "value", onlychanged=True, queued=True)
main_layout = pn.Row(slice1.getMainLayout(), slice2.getMainLayout())
main_layout.servable()

else:

slice = Slice()
slice.load(sys.argv[1])

# load a whole scene
if "load" in query_params:
body = json.loads(base64.b64decode(query_params['load']).decode("utf-8"))
slice.setBody(body)

# select from list of choices
elif "dataset" in query_params:
scene_name = query_params["dataset"]
slice.scene.value = scene_name

main_layout = slice.getMainLayout()
main_layout.servable()

pn.extension(
"ipywidgets",
"floatpanel",
"codeeditor",
log_level="DEBUG",
notifications=True,
)

query_params = {k: v for k, v in pn.state.location.query_params.items()}

log_filename = os.environ.get("OPENVISUSPY_DASHBOARDS_LOG_FILENAME", "/tmp/openvisuspy-dashboards.log")
logger = SetupLogger(log_filename=log_filename, logging_level=logging.DEBUG)

# Sync view
if len(sys.argv[1:]) == 2:

slice1 = Slice()
slice1.load(sys.argv[1])
slice2 = Slice()
slice2.load(sys.argv[2])

show_options = {
"top": [
[
"palette",
"color_mapper_type",
"resolution",
"num_refinements",
"field",
"range_mode",
"range_min",
"range_max"
],
],
}
slice1.setShowOptions(show_options)
slice2.setShowOptions(show_options)

# Define update functions with throttling
def update_slice2(attr, old, new):
throttle(SyncSlices, slice1, slice2)

def update_slice1(attr, old, new):
throttle(SyncSlicesReverse, slice2, slice1)

# Watch for viewport changes in slice1 and slice2 using on_change
slice1.canvas.fig.x_range.on_change('start', update_slice2)
slice1.canvas.fig.x_range.on_change('end', update_slice2)
slice1.canvas.fig.y_range.on_change('start', update_slice2)
slice1.canvas.fig.y_range.on_change('end', update_slice2)

slice2.canvas.fig.x_range.on_change('start', update_slice1)
slice2.canvas.fig.x_range.on_change('end', update_slice1)
slice2.canvas.fig.y_range.on_change('start', update_slice1)
slice2.canvas.fig.y_range.on_change('end', update_slice1)

# Layout for both slices
main_layout = pn.Row(slice1.getMainLayout(), slice2.getMainLayout())
main_layout.servable()

else:
slice = Slice()
slice.load(sys.argv[1])

# Load a whole scene
if "load" in query_params:
body = json.loads(base64.b64decode(query_params['load']).decode("utf-8"))
slice.setBody(body)

# Select from list of choices
elif "dataset" in query_params:
scene_name = query_params["dataset"]
slice.scene.value = scene_name

main_layout = slice.getMainLayout()
main_layout.servable()
64 changes: 44 additions & 20 deletions src/openvisuspy/show_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
from bokeh.models import LinearColorMapper
import bokeh.models
import logging
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
from bokeh.models import ColumnDataSource, ColorBar, LinearColorMapper
from .utils import *

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -106,7 +110,7 @@ def ShowDetails(self,x,y,w,h):
pdim=self.getPointDim()

# todo for 2D dataset
assert(pdim==3)
# assert(pdim==3)

z=int(self.offset.value)
logic_box=self.toLogic([x,y,w,h])
Expand Down Expand Up @@ -148,29 +152,49 @@ def ShowDetails(self,x,y,w,h):
self.range_min.value = min(self.range_min.value, self.vmin)
self.range_max.value = max(self.range_max.value, self.vmax)
logger.info(f"Updating range with selected area vmin={self.vmin} vmax={self.vmax}")

p = figure(x_range=(self.selected_physic_box[0][0], self.selected_physic_box[0][1]), y_range=(self.selected_physic_box[1][0], self.selected_physic_box[1][1]))
fig, ax = plt.subplots()

p1 = figure(x_range=(0,100), y_range=(0,100))
palette_name = self.palette.value_name if self.palette.value_name.endswith("256") else "Turbo256"

mapper = LinearColorMapper(palette=palette_name, low=np.min(self.detailed_data), high=np.max(self.detailed_data))

# Flip data to match imshow orientation
data_flipped = data
source = bokeh.models.ColumnDataSource(data=dict(image=[data_flipped]))
data_flipped = data

print(type(self.selected_physic_box[0][1]))
dw = abs(self.selected_physic_box[0][1] -self.selected_physic_box[0][0])

dh = abs(self.selected_physic_box[1][1] - self.selected_physic_box[1][0])
p.image(image='image', x=self.selected_physic_box[0][0], y=self.selected_physic_box[1][0], dw=dw, dh=dh, color_mapper=mapper, source=source)
color_bar = bokeh.models.ColorBar(color_mapper=mapper, label_standoff=12, location=(0,0))
p.add_layout(color_bar, 'right')
p.xaxis.axis_label = "X"
p.yaxis.axis_label = "Y"

self.showDialog(
pn.Column(
self.file_name_input,
pn.Row(save_numpy_button,download_script_button),
pn.Row(apply_avg_min_colormap_button,apply_avg_max_colormap_button,add_range_button,apply_colormap_button),
pn.Row(pn.pane.Bokeh(p,sizing_mode="stretch_both")),
sizing_mode="stretch_both"
)
, width=900, height=800, name=f"Palette: {palette_name} Min: {self.vmin}, Max: {self.vmax}")
x_min, x_max = int(self.selected_physic_box[0][0]), int(self.selected_physic_box[0][1])
y_min, y_max = int(self.selected_physic_box[1][0]), int(self.selected_physic_box[1][1])

#fig, ax = plt.subplots(figsize=(14, 20))
fig, ax = plt.subplots(figsize=(4, 4))
im = ax.imshow(data_flipped, cmap='turbo',extent=[x_min, x_max, y_min, y_max], aspect='auto')
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.1)
cbar = plt.colorbar(im, cax=cax)

ax.set_xlim(self.selected_physic_box[0][0], self.selected_physic_box[0][1])
ax.set_ylim(self.selected_physic_box[1][1], self.selected_physic_box[1][0])

ax.set_xlabel("X")
ax.set_ylabel("Y")
plt.tight_layout()

dialog_layout = pn.Column(
self.file_name_input,
pn.Row(save_numpy_button, download_script_button),
pn.Row(pn.pane.Matplotlib(fig), pn.Column(
pn.pane.Markdown(f"#### Palette Used: {palette_name}"),
pn.pane.Markdown(f"#### New Min/Max Found.."),
pn.pane.Markdown(f"#### Min: {self.vmin}, Max: {self.vmax}"),
pn.Row(apply_avg_min_colormap_button, apply_avg_max_colormap_button),
add_range_button,
apply_colormap_button
)),
sizing_mode="stretch_both"
)

self.showDialog(dialog_layout, width=500, height=600, name="Details")

0 comments on commit cce60ca

Please sign in to comment.