6
6
from glue_jupyter .bqplot .image .state import BqplotImageViewerState
7
7
from glue .viewers .matplotlib .state import DeferredDrawCallbackProperty as DDCProperty
8
8
9
+ from jdaviz .configs .imviz .helper import get_reference_image_data
10
+
9
11
__all__ = ['FreezableState' , 'FreezableProfileViewerState' , 'FreezableBqplotImageViewerState' ]
10
12
11
13
@@ -55,16 +57,16 @@ def _reset_x_limits(self, *event):
55
57
class FreezableBqplotImageViewerState (BqplotImageViewerState , FreezableState ):
56
58
linked_by_wcs = False
57
59
58
- zoom_level = CallbackProperty (1.0 , docstring = ' Zoom-level' )
60
+ zoom_radius = CallbackProperty (1.0 , docstring = " Zoom radius" )
59
61
zoom_center_x = CallbackProperty (0.0 , docstring = 'x-coordinate of center of zoom box' )
60
62
zoom_center_y = CallbackProperty (0.0 , docstring = 'y-coordinate of center of zoom box' )
61
63
62
64
def __init__ (self , * args , ** kwargs ):
63
65
self .wcs_only_layers = [] # For Imviz rotation use.
64
66
self ._during_zoom_sync = False
65
- self .add_callback ('zoom_level ' , self ._set_zoom_level )
66
- self .add_callback ('zoom_center_x' , self ._set_zoom_center )
67
- self .add_callback ('zoom_center_y' , self ._set_zoom_center )
67
+ self .add_callback ('zoom_radius ' , self ._set_zoom_radius_center )
68
+ self .add_callback ('zoom_center_x' , self ._set_zoom_radius_center )
69
+ self .add_callback ('zoom_center_y' , self ._set_zoom_radius_center )
68
70
for attr in ('x_min' , 'x_max' , 'y_min' , 'y_max' ):
69
71
self .add_callback (attr , self ._set_axes_lim )
70
72
super ().__init__ (* args , ** kwargs )
@@ -79,40 +81,34 @@ def during_zoom_sync(self):
79
81
raise
80
82
self ._during_zoom_sync = False
81
83
82
- def _set_zoom_level (self , zoom_level ):
84
+ def _set_zoom_radius_center (self , * args ):
83
85
if self ._during_zoom_sync or not hasattr (self , '_viewer' ) or self ._viewer .shape is None :
84
86
return
85
- if zoom_level <= 0.0 :
86
- raise ValueError ("zoom_level must be positive" )
87
-
88
- cur_xcen = (self .x_min + self .x_max ) * 0.5
89
- new_dx = self ._viewer .shape [1 ] * 0.5 / zoom_level
90
- new_x_min = cur_xcen - new_dx
91
- new_x_max = cur_xcen + new_dx
87
+ if self .zoom_radius <= 0.0 :
88
+ raise ValueError ("zoom_radius must be positive" )
89
+
90
+ # When WCS-linked (displayed on the sky): zoom_center_x/y and zoom_radius are in sky units,
91
+ # x/y_min/max are in pixels of the WCS-only layer
92
+ if self .linked_by_wcs :
93
+ image , i_ref = get_reference_image_data (self ._viewer .jdaviz_app , self ._viewer .reference )
94
+ ref_wcs = image .coords
95
+ center_x , center_y = ref_wcs .world_to_pixel_values (self .zoom_center_x , self .zoom_center_y ) # noqa
96
+ center_xr , center_yr = ref_wcs .world_to_pixel_values (self .zoom_center_x + self .zoom_radius , self .zoom_center_y ) # noqa
97
+ radius = abs (center_xr - center_x )
98
+ else :
99
+ center_x , center_y = self .zoom_center_x , self .zoom_center_y
100
+ radius = self .zoom_radius
101
+ # now center_x/y and radius are in pixel units of the reference data, so can be used to
102
+ # update limits
92
103
93
104
with self .during_zoom_sync ():
94
- self .x_min = new_x_min - 0.5
95
- self .x_max = new_x_max - 0.5
105
+ self .x_min = center_x - radius
106
+ self .x_max = center_x + radius
107
+ self .y_min = center_y - radius
108
+ self .y_max = center_y + radius
96
109
97
- # We need to adjust the limits in here to avoid triggering all
98
- # the update events then changing the limits again.
99
110
self ._adjust_limits_aspect ()
100
111
101
- def _set_zoom_center (self , * args ):
102
- if self ._during_zoom_sync :
103
- return
104
-
105
- cur_xcen = (self .x_min + self .x_max ) * 0.5
106
- cur_ycen = (self .y_min + self .y_max ) * 0.5
107
- delta_x = self .zoom_center_x - cur_xcen
108
- delta_y = self .zoom_center_y - cur_ycen
109
-
110
- with self .during_zoom_sync ():
111
- self .x_min += delta_x
112
- self .x_max += delta_x
113
- self .y_min += delta_y
114
- self .y_max += delta_y
115
-
116
112
def _set_axes_aspect_ratio (self , axes_ratio ):
117
113
# when aspect-ratio is changed (changing viewer.shape), ensure zoom/center are synced
118
114
# with zoom-limits
@@ -125,17 +121,22 @@ def _set_axes_lim(self, *args):
125
121
if None in (self .x_min , self .x_max , self .y_min , self .y_max ):
126
122
return
127
123
128
- screenx = self ._viewer .shape [1 ]
129
- screeny = self ._viewer .shape [0 ]
130
- zoom_x = screenx / (self .x_max - self .x_min )
131
- zoom_y = screeny / (self .y_max - self .y_min )
132
- center_x = 0.5 * (self .x_max + self .x_min )
133
- center_y = 0.5 * (self .y_max + self .y_min )
124
+ # When WCS-linked (displayed on the sky): zoom_center_x/y and zoom_radius are in sky units,
125
+ # x/y_min/max are in pixels of the WCS-only layer
126
+ if self .linked_by_wcs :
127
+ image , i_ref = get_reference_image_data (self ._viewer .jdaviz_app , self ._viewer .reference )
128
+ ref_wcs = image .coords
129
+ x_min , y_min = ref_wcs .pixel_to_world_values (self .x_min , self .y_min )
130
+ x_max , y_max = ref_wcs .pixel_to_world_values (self .x_max , self .y_max )
131
+ else :
132
+ x_min , y_min = self .x_min , self .y_min
133
+ x_max , y_max = self .x_max , self .y_max
134
+ # now x_min/max, y_min/max are in axes units (degrees if WCS-linked, pixels otherwise)
134
135
135
136
with self .during_zoom_sync ():
136
- self .zoom_level = max ( zoom_x , zoom_y ) # Similar to Ginga get_scale( )
137
- self .zoom_center_x = center_x
138
- self .zoom_center_y = center_y
137
+ self .zoom_radius = abs ( 0.5 * min ( x_max - x_min , y_max - y_min ) )
138
+ self .zoom_center_x = 0.5 * ( x_max + x_min )
139
+ self .zoom_center_y = 0.5 * ( y_max + y_min )
139
140
140
141
def reset_limits (self , * event ):
141
142
# TODO: use consistent logic for all image viewers by removing this if-statement
0 commit comments