-
-
Notifications
You must be signed in to change notification settings - Fork 15
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
Move interface definition from base class to protocol #162
Changes from all commits
62f6b97
a8f7cbd
e735a23
38cdcd7
9ad7797
aa84748
9baba2b
e7e5f5c
9dffe05
75bc9df
367d61f
f23ed64
fc0056f
e9afc48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
from typing import Protocol, runtime_checkable, Any | ||
from abc import abstractmethod | ||
|
||
# Allowed locations for cursor display | ||
ALLOWED_CURSOR_LOCATIONS = ('top', 'bottom', None) | ||
|
||
# List of marker names that are for internal use only | ||
RESERVED_MARKER_SET_NAMES = ('all',) | ||
|
||
__all__ = [ | ||
'ImageViewerInterface', | ||
'ALLOWED_CURSOR_LOCATIONS', | ||
'RESERVED_MARKER_SET_NAMES' | ||
] | ||
|
||
|
||
@runtime_checkable | ||
class ImageViewerInterface(Protocol): | ||
# These are attributes, not methods. The type annotations are there | ||
# to make sure Protocol knows they are attributes. Python does not | ||
# do any checking at all of these types. | ||
Comment on lines
+20
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could enforce it with third-party type checker package but is that going too far? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, although it's a bit odd, when I think about it I like the cleanness of the interface not doing any checking but the APITest class doing it. So maybe if we implemented type-checking it could use this information but actually do the type checking when the APITest is invoked by a backend? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I should clarify -- I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if we want to enforce run-time checking. Might be too controversial. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed -- and the way we have set things up I don't think we can. |
||
click_center: bool | ||
click_drag: bool | ||
scroll_pan: bool | ||
image_width: int | ||
image_height: int | ||
zoom_level: float | ||
is_marking: bool | ||
stretch_options: tuple | ||
autocut_options: tuple | ||
cursor: str | ||
marker: Any | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These were omitted the first time through:
|
||
cuts: Any | ||
stretch: str | ||
# viewer: Any | ||
|
||
# Allowed locations for cursor display | ||
ALLOWED_CURSOR_LOCATIONS: tuple = ALLOWED_CURSOR_LOCATIONS | ||
|
||
# List of marker names that are for internal use only | ||
RESERVED_MARKER_SET_NAMES: tuple = RESERVED_MARKER_SET_NAMES | ||
|
||
# The methods, grouped loosely by purpose | ||
|
||
# Methods for loading data | ||
@abstractmethod | ||
def load_fits(self, file): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know you say API change is out of scope, but I want to note that we agreed at Astropy Coordination Meeting 2023 to change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks -- I added this to the agenda in the running notes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I opened #163 |
||
""" | ||
Load a FITS file into the viewer. | ||
|
||
Parameters | ||
---------- | ||
file : str or `astropy.io.fits.HDU` | ||
The FITS file to load. If a string, it can be a URL or a | ||
file path. | ||
""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def load_array(self, array): | ||
""" | ||
Load a 2D array into the viewer. | ||
|
||
Parameters | ||
---------- | ||
array : array-like | ||
The array to load. | ||
""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def load_nddata(self, data): | ||
""" | ||
Load an `astropy.nddata.NDData` object into the viewer. | ||
|
||
Parameters | ||
---------- | ||
data : `astropy.nddata.NDData` | ||
The NDData object to load. | ||
""" | ||
raise NotImplementedError | ||
|
||
# Saving contents of the view and accessing the view | ||
@abstractmethod | ||
def save(self, filename): | ||
""" | ||
Save the current view to a file. | ||
|
||
Parameters | ||
---------- | ||
filename : str | ||
The file to save to. The format is determined by the | ||
extension. | ||
""" | ||
raise NotImplementedError | ||
|
||
# Marker-related methods | ||
@abstractmethod | ||
def start_marking(self, marker_name=None): | ||
""" | ||
Start interactive marking of points on the image. | ||
|
||
Parameters | ||
---------- | ||
marker_name : str, optional | ||
The name of the marker set to use. If not given, a unique | ||
name will be generated. | ||
""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def stop_marking(self, clear_markers=False): | ||
""" | ||
Stop interactive marking of points on the image. | ||
|
||
Parameters | ||
---------- | ||
clear_markers : bool, optional | ||
If `True`, clear the markers that were created during | ||
interactive marking. Default is `False`. | ||
""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def add_markers(self, table, x_colname='x', y_colname='y', | ||
skycoord_colname='coord', use_skycoord=False, | ||
marker_name=None): | ||
""" | ||
Add markers to the image. | ||
|
||
Parameters | ||
---------- | ||
table : `astropy.table.Table` | ||
The table containing the marker positions. | ||
x_colname : str, optional | ||
The name of the column containing the x positions. Default | ||
is ``'x'``. | ||
y_colname : str, optional | ||
The name of the column containing the y positions. Default | ||
is ``'y'``. | ||
skycoord_colname : str, optional | ||
The name of the column containing the sky coordinates. If | ||
given, the ``use_skycoord`` parameter is ignored. Default | ||
is ``'coord'``. | ||
use_skycoord : bool, optional | ||
If `True`, the ``skycoord_colname`` column will be used to | ||
get the marker positions. Default is `False`. | ||
marker_name : str, optional | ||
The name of the marker set to use. If not given, a unique | ||
name will be generated. | ||
""" | ||
raise NotImplementedError | ||
|
||
# @abstractmethod | ||
# def remove_all_markers(self): | ||
# raise NotImplementedError | ||
|
||
@abstractmethod | ||
def reset_markers(self): | ||
""" | ||
Remove all markers from the image. | ||
""" | ||
raise NotImplementedError | ||
|
||
# @abstractmethod | ||
# def remove_markers_by_name(self, marker_name=None): | ||
# raise NotImplementedError | ||
|
||
@abstractmethod | ||
def remove_markers(self, marker_name=None): | ||
""" | ||
Remove markers from the image. | ||
|
||
Parameters | ||
---------- | ||
marker_name : str, optional | ||
The name of the marker set to remove. If not given, all | ||
markers will be removed. | ||
""" | ||
raise NotImplementedError | ||
|
||
# @abstractmethod | ||
# def get_all_markers(self): | ||
# raise NotImplementedError | ||
|
||
@abstractmethod | ||
def get_markers(self, x_colname='x', y_colname='y', | ||
skycoord_colname='coord', | ||
marker_name=None): | ||
""" | ||
Get the marker positions. | ||
|
||
Parameters | ||
---------- | ||
x_colname : str, optional | ||
The name of the column containing the x positions. Default | ||
is ``'x'``. | ||
y_colname : str, optional | ||
The name of the column containing the y positions. Default | ||
is ``'y'``. | ||
skycoord_colname : str, optional | ||
The name of the column containing the sky coordinates. Default | ||
is ``'coord'``. | ||
marker_name : str, optional | ||
The name of the marker set to use. If not given, all | ||
markers will be returned. | ||
|
||
Returns | ||
------- | ||
table : `astropy.table.Table` | ||
The table containing the marker positions. | ||
""" | ||
raise NotImplementedError | ||
|
||
# Methods that modify the view | ||
@abstractmethod | ||
def center_on(self, point): | ||
""" | ||
Center the view on the point. | ||
|
||
Parameters | ||
---------- | ||
tuple or `~astropy.coordinates.SkyCoord` | ||
If tuple of ``(X, Y)`` is given, it is assumed | ||
to be in data coordinates. | ||
""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def offset_by(self, dx, dy): | ||
""" | ||
Move the center to a point that is given offset | ||
away from the current center. | ||
|
||
Parameters | ||
---------- | ||
dx, dy : float or `~astropy.unit.Quantity` | ||
Offset value. Without a unit, assumed to be pixel offsets. | ||
If a unit is attached, offset by pixel or sky is assumed from | ||
the unit. | ||
""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def zoom(self): | ||
""" | ||
Zoom in or out by the given factor. | ||
|
||
Parameters | ||
---------- | ||
val : int | ||
The zoom level to zoom the image. | ||
See `zoom_level`. | ||
""" | ||
raise NotImplementedError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you say API change is out of scope, but I want to note that we agreed at Astropy Coordination Meeting 2023 to move backend specific implementations (ginga, bqplot, Firefly, etc) out of
astrowidgets
repo.https://docs.google.com/document/d/1sBImbw1p4mM3VYWGQJDRbj2N3uqP5Ed_Wfb8BDjJj2o/edit#heading=h.8ah2ugluz5xr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened #164 and #165