@@ -29,6 +29,8 @@ class ImageViewer:
2929 autocut_options : tuple = ("minmax" , "zscale" , "asinh" , "percentile" , "histogram" )
3030 _cursor : str = ImageViewerInterface .ALLOWED_CURSOR_LOCATIONS [0 ]
3131 _markers : dict [str , dict ] = field (default_factory = dict )
32+ _catalogs : dict [str , Table ] = field (default_factory = dict )
33+ _catalog_names : list [str ] = field (default_factory = list )
3234 _default_marker_style : dict [str , Any ] = field (default_factory = dict )
3335 _cuts : str | tuple [float , float ] = (0 , 1 )
3436 _stretch : str = "linear"
@@ -47,6 +49,30 @@ def __post_init__(self):
4749 self ._default_marker_style = dict (shape = "circle" , color = "yellow" , size = 10 )
4850 self ._markers [None ] = self ._default_marker_style .copy ()
4951
52+ def _user_catalog_labels (self ) -> list [str ]:
53+ """
54+ Get the user-defined catalog labels.
55+ """
56+ return [label for label in self ._markers if label is not None ]
57+
58+ def _resolve_catalog_label (self , catalog_label : str | None ) -> list [str ]:
59+ user_keys = self ._user_catalog_labels ()
60+ if catalog_label is None :
61+ match len (user_keys ):
62+ case 0 :
63+ # No user-defined styles, so return the default style
64+ catalog_label = None
65+ case 1 :
66+ # The user must have set a style, so return that instead of
67+ # the default style, which live in the key None.
68+ catalog_label = user_keys [0 ]
69+ case _:
70+ raise ValueError (
71+ "Multiple catalog styles defined. Please specify a catalog_label to get the style."
72+ )
73+
74+ return catalog_label
75+
5076 @property
5177 def stretch (self ) -> str :
5278 return self ._stretch
@@ -100,20 +126,7 @@ def get_catalog_style(self, catalog_label=None) -> dict[str, dict[str, Any]]:
100126 dict
101127 The style for the catalog.
102128 """
103- user_keys = list (set (self ._markers .keys ()) - {None })
104- if catalog_label is None :
105- match len (user_keys ):
106- case 0 :
107- # No user-defined styles, so return the default style
108- catalog_label = None
109- case 1 :
110- # The user must have set a style, so return that instead of
111- # the default style, which live in the key None.
112- catalog_label = user_keys [0 ]
113- case _:
114- raise ValueError (
115- "Multiple catalog styles defined. Please specify a catalog_label to get the style."
116- )
129+ catalog_label = self ._resolve_catalog_label (catalog_label )
117130
118131 style = self ._markers [catalog_label ]
119132 style ["catalog_label" ] = catalog_label
@@ -228,9 +241,9 @@ def save(self, filename: str | os.PathLike, overwrite: bool = False) -> None:
228241 p .write_text ("This is a dummy file. The viewer does not save anything." )
229242
230243 # Marker-related methods
231- def add_markers (self , table : Table , x_colname : str = 'x' , y_colname : str = 'y' ,
244+ def load_catalog (self , table : Table , x_colname : str = 'x' , y_colname : str = 'y' ,
232245 skycoord_colname : str = 'coord' , use_skycoord : bool = False ,
233- marker_name : str | None = None ) -> None :
246+ catalog_label : str | None = None ) -> None :
234247 """
235248 Add markers to the image.
236249
@@ -251,7 +264,7 @@ def add_markers(self, table: Table, x_colname: str = 'x', y_colname: str = 'y',
251264 use_skycoord : bool, optional
252265 If `True`, the ``skycoord_colname`` column will be used to
253266 get the marker positions. Default is `False`.
254- marker_name : str, optional
267+ catalog_label : str, optional
255268 The name of the marker set to use. If not given, a unique
256269 name will be generated.
257270 """
@@ -279,86 +292,55 @@ def add_markers(self, table: Table, x_colname: str = 'x', y_colname: str = 'y',
279292 coord = coords if coords else [None ] * len (x ),
280293 )
281294 )
282- to_add ["marker name" ] = marker_name
283295
284- if marker_name in self ._markers :
285- marker_table = self ._markers [marker_name ]
286- self ._markers [marker_name ] = vstack ([marker_table , to_add ])
296+ catalog_label = self ._resolve_catalog_label (catalog_label )
297+ if catalog_label in self ._catalogs :
298+ marker_table = self ._markers [catalog_label ]
299+ self ._markers [catalog_label ] = vstack ([marker_table , to_add ])
287300 else :
288- self ._markers [marker_name ] = to_add
289-
290- def reset_markers (self ) -> None :
291- """
292- Remove all markers from the image.
293- """
294- self ._markers = {}
301+ self ._markers [catalog_label ] = to_add
295302
296- def remove_markers (self , marker_name : str | list [ str ] | None = None ) -> None :
303+ def remove_catalog (self , catalog_label : str | None = None ) -> None :
297304 """
298305 Remove markers from the image.
299306
300307 Parameters
301308 ----------
302309 marker_name : str, optional
303- The name of the marker set to remove. If the value is ``"all "``,
310+ The name of the marker set to remove. If the value is ``"* "``,
304311 then all markers will be removed.
305312 """
306- if isinstance (marker_name , str ):
307- if marker_name in self ._markers :
308- del self ._markers [marker_name ]
309- elif marker_name == "all " :
313+ if isinstance (catalog_label , str ):
314+ if catalog_label in self ._markers :
315+ del self ._markers [catalog_label ]
316+ elif catalog_label == "* " :
310317 self ._markers = {}
311318 else :
312- raise ValueError (f"Marker name { marker_name } not found." )
313- elif isinstance (marker_name , list ):
314- for name in marker_name :
319+ raise ValueError (f"Marker name { catalog_label } not found." )
320+ elif isinstance (catalog_label , list ):
321+ for name in catalog_label :
315322 if name in self ._markers :
316323 del self ._markers [name ]
317324 else :
318325 raise ValueError (f"Marker name { name } not found." )
319326
320- def get_markers (self , x_colname : str = 'x' , y_colname : str = 'y' ,
327+ def get_catalog (self , x_colname : str = 'x' , y_colname : str = 'y' ,
321328 skycoord_colname : str = 'coord' ,
322- marker_name : str | list [str ] | None = None ) -> Table :
323- """
324- Get the marker positions.
325-
326- Parameters
327- ----------
328- x_colname : str, optional
329- The name of the column containing the x positions. Default
330- is ``'x'``.
331- y_colname : str, optional
332- The name of the column containing the y positions. Default
333- is ``'y'``.
334- skycoord_colname : str, optional
335- The name of the column containing the sky coordinates. Default
336- is ``'coord'``.
337- marker_name : str or list of str, optional
338- The name of the marker set to use. If that value is ``"all"``,
339- then all markers will be returned.
340-
341- Returns
342- -------
343- table : `astropy.table.Table`
344- The table containing the marker positions. If no markers match the
345- ``marker_name`` parameter, an empty table is returned.
346- """
347- if isinstance (marker_name , str ):
348- if marker_name == "all" :
349- marker_name = self ._markers .keys ()
350- else :
351- marker_name = [marker_name ]
352- elif marker_name is None :
353- marker_name = ["_default_marker" ]
329+ catalog_label : str | None = None ) -> Table :
330+ # Dostring is copied from the interface definition, so it is not
331+ # duplicated here.
332+ catalog_label = self ._resolve_catalog_label (catalog_label )
354333
355- to_stack = [ self ._markers [name ] for name in marker_name if name in self ._markers ]
334+ result = self ._markers [catalog_label ] if catalog_label in self ._markers else Table ( names = [ "x" , "y" , "coord" , "marker name" ])
356335
357- result = vstack (to_stack ) if to_stack else Table (names = ["x" , "y" , "coord" , "marker name" ])
358336 result .rename_columns (["x" , "y" , "coord" ], [x_colname , y_colname , skycoord_colname ])
359337
360338 return result
339+ get_catalog .__doc__ = ImageViewerInterface .get_catalog .__doc__
361340
341+ def get_catalog_names (self ) -> list [str ]:
342+ return list (self ._user_catalog_labels ())
343+ get_catalog_names .__doc__ = ImageViewerInterface .get_catalog_names .__doc__
362344
363345 # Methods that modify the view
364346 def center_on (self , point : tuple | SkyCoord ):
0 commit comments