Skip to content

Commit

Permalink
Added Zoom Level Feature and Super-Resolution image can be kept left/…
Browse files Browse the repository at this point in the history
…Right slice
  • Loading branch information
Sampad530 committed Feb 11, 2025
1 parent 2f0d451 commit 0e62324
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 31 deletions.
123 changes: 94 additions & 29 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,45 @@
from sync_link import SliceSynchronizer


#####################################################################

'''
Syncronized zooming and updated zomm level
'''
class ZoomSync:
def __init__(self, slice1, slice2, scale_factor, slice1_caption, slice2_caption):
self.synchronizer = SliceSynchronizer(slice1, slice2, scale_factor) # Synchronizer for slices
self.synchronizer.register_callback(self.on_zoom_update)

# Store reference to captions for updates
self.slice1_caption = slice1_caption
self.slice2_caption = slice2_caption

def update_caption(self, caption, label, zoom_level):
"""
Helper method to update captions dynamically.
"""
caption.object = f"""
<div style="text-align: top; height: auto;">
<h4> {label} &nbsp;&nbsp;&nbsp; Zoom Level: {round(zoom_level, 2)} %</h4>
</div>
"""

def on_zoom_update(self, zoom_level_fig1, zoom_level_fig2):
"""
Callback function to update zoom levels in captions.
"""
print(f"Updated Zoom Levels - Fig1: {zoom_level_fig1}, Fig2: {zoom_level_fig2}")
self.update_caption(self.slice1_caption, slice1.image_type.value, zoom_level_fig1)
self.update_caption(self.slice2_caption, slice2.image_type.value, zoom_level_fig2)

def run(self):
"""
Run the application.
"""
print("Application is running...")


#####################################################################

def get_file_path():
Expand All @@ -34,6 +73,9 @@ def get_file_path():
logger.info(f"Command Line Args: {cmd_args}")
return cmd_args


#####################################################################

if __name__.startswith('bokeh'):
pn.extension(
"ipywidgets",
Expand All @@ -52,10 +94,21 @@ def get_file_path():
# Show options for both slices
# "resolution" max , "view_dependent" is yes; set Default

show_options = {
"top": [["scene", "resolution","view_dependent"]], # color_mapper_type, Pallete, field, range mode max min are removed
"bottom": [["request", "response"]],
}
'''
show_options={
"top": [
[ "menu_button","scene", "timestep", "timestep_delta", "play_sec","play_button","palette", "color_mapper_type","view_dependent", "resolution", "num_refinements", "show_probe"],
["field","direction", "offset", "range_mode", "range_min", "range_max"]
],
"bottom": [
["request","response", "zoom_level", "image_type"]
]
}
'''

show_options = {}

args = get_file_path()
logger.info(f"Final Args Being Used: {args}")
Expand All @@ -64,17 +117,26 @@ def get_file_path():
logger.info(f"Using two-file sync view mode with files: {args[0]} and {args[1]}")
# Load for Sync Slices view
slice1 = Slice(ViewChoice="SYNC_VIEW")
slice1.load(args[0])
slice1.load(sys.argv[1])

slice2 = Slice(ViewChoice="SYNC_VIEW")
slice2.load(args[1])
slice2.load(sys.argv[2])


# Compute scale factor
box1 = slice1.db.getPhysicBox()
box2 = slice2.db.getPhysicBox()
scale_factor = box2[0][1] / box1[0][1] # Scaling based on x-axis


if scale_factor < 1: # reverse both images
slice1.image_type.value = "Super-Resolution Image"
slice2.image_type.value = "Original Image"
else:
slice1.image_type.value = "Original Image"
slice2.image_type.value = "Super-Resolution Image"


slice1.setShowOptions(show_options)
slice2.setShowOptions(show_options)

Expand All @@ -86,12 +148,11 @@ def get_file_path():
f"""
<div style="
display: flex;
justify-content: center;
align-items: center;
text-align: center;
height: 100%;
font-size: 24px;">
<h4>Original Image &nbsp;({int(box1[0][1])} x {int(box1[1][1])})</h4>
justify-content: top;
align-items: top;
text-align: top;
height: 5;">
<h4>Original Image </h4>
</div>
""",
sizing_mode="stretch_width", # Ensures full width for centering
Expand All @@ -101,34 +162,38 @@ def get_file_path():
f"""
<div style="
display: flex;
justify-content: center;
align-items: center;
text-align: center;
height: 100%;
font-size: 24px;">
<h4>Super-Resolution Image &nbsp;({int(box2[0][1])} x {int(box2[1][1])})&nbsp;&nbsp;&nbsp; Scale Factor: {scale_factor:.2f}</h4>
justify-content: top;
align-items: top;
text-align: top;
height: 5;">
<h4>Super-Resolution Image </h4>
</div>
""",
sizing_mode="stretch_width", # Ensures full width for centering
)

# Synchronizer for slices
synchronizer = SliceSynchronizer(slice1, slice2, scale_factor)

# Initialize the ZoomSync class
zoom_sync = ZoomSync(slice1, slice2, scale_factor, slice1_caption,slice2_caption)
zoom_sync.run()

# Add the buttons to the layout
layout = pn.Row(
pn.Column(
slice1_caption,
slice1.getMainLayout(),
layout = pn.Column(
pn.Row(
pn.Column(
slice1.getMainLayout(),
sizing_mode="stretch_both",
),
pn.Column(
slice2.getMainLayout(),
sizing_mode="stretch_both",
),
sizing_mode="stretch_both",
),
pn.Column(
slice2_caption,
slice2.getMainLayout(),
pn.Row(
slice1_caption, slice2_caption,
sizing_mode="stretch_both",
),
sizing_mode="stretch_both",
)
)
layout.servable()
else:
Expand Down
50 changes: 49 additions & 1 deletion app/sync_link.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
from bokeh.models import CustomJS
from threading import Timer
import math


class SliceSynchronizer:
def __init__(self, slice1, slice2, scale_factor=4):
self.slice1 = slice1
self.slice2 = slice2
self.scale_factor = scale_factor
self.full_width = None
self.debounce_timer = None # Timer to debounce refresh calls
self.debounce_delay = 0.1 # Delay in seconds for debounce
self.update_callbacks = [] # Callback list for external

# Store zoom levels
self.zoom_level_1 = 1.0 #intial value
self.zoom_level_2 = 1.0

# Link ranges with JavaScript callbacks
self.link_ranges()
Expand Down Expand Up @@ -64,6 +71,11 @@ def trigger_refresh():
self.slice1.refresh("DebouncedSyncFromSlice2")
self.slice2.refresh("DebouncedSyncFromSlice1")

self.zoom_level_1= self.update_zoom_level(fig1)
self.zoom_level_2= self.update_zoom_level(fig2)

self.notify_subscribers()

def debounce_refresh(attr, old, new):
"""Debounce refresh calls."""
if self.debounce_timer:
Expand All @@ -82,4 +94,40 @@ def debounce_refresh(attr, old, new):
fig2.x_range.on_change('start', debounce_refresh)
fig2.x_range.on_change('end', debounce_refresh)
fig2.y_range.on_change('start', debounce_refresh)
fig2.y_range.on_change('end', debounce_refresh)
fig2.y_range.on_change('end', debounce_refresh)


#Zoom level Calculation
def update_zoom_level(self, fig):
"""
Calculate and update the zoom level dynamically.
"""
# Get current viewport size
image_width = fig.x_range.end - fig.x_range.start

# Prevent division by zero
image_width = max(1, image_width)

viewport_width = fig.inner_width

zoomLevel = (viewport_width / math.ceil(image_width)) * 100

print(f"zoom: viewport width={viewport_width}, image width={math.ceil(image_width)}, zoomLevel={zoomLevel}%")


return (zoomLevel) # Return the zoom level


def register_callback(self, callback):
"""
Register a callback function to be notified when zoom levels are updated.
The callback function should accept two arguments: (zoom_level_fig1, zoom_level_fig2).
"""
self.update_callbacks.append(callback)

def notify_subscribers(self):
"""
Notify all registered subscribers with the updated zoom levels.
"""
for callback in self.update_callbacks:
callback(self.zoom_level_1, self.zoom_level_2)
4 changes: 3 additions & 1 deletion src/openvisuspy/slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class Slice(param.Parameterized):

],
"bottom": [
["request","response"]
["request","response","image_type"]
]
}

Expand Down Expand Up @@ -577,6 +577,8 @@ def onColorMapperTypeChange(evt):
self.request = pn.widgets.TextInput(name="", sizing_mode='stretch_width', disabled=False)
self.response = pn.widgets.TextInput(name="", sizing_mode='stretch_width', disabled=False)

self.image_type = pn.widgets.TextInput(name="", sizing_mode='stretch_width', disabled=False) # Sync-View Image Title

self.file_name_input = pn.widgets.TextInput(name="Numpy_File", value='test', placeholder='Numpy File Name to save')

self.canvas = Canvas(self.id, self.view_choice)
Expand Down

0 comments on commit 0e62324

Please sign in to comment.