@@ -201,7 +201,7 @@ def get_sectors(self, *, coordinates=None, radius=0*u.deg, objectname=None, movi
201
201
return Table (sector_dict )
202
202
203
203
def download_cutouts (self , * , coordinates = None , size = 5 , sector = None , path = "." , inflate = True ,
204
- objectname = None , moving_target = False , mt_type = None ):
204
+ objectname = None , moving_target = False , mt_type = None , verbose = False ):
205
205
"""
206
206
Download cutout target pixel file(s) around the given coordinates with indicated size.
207
207
@@ -301,7 +301,7 @@ def download_cutouts(self, *, coordinates=None, size=5, sector=None, path=".", i
301
301
localpath_table ['Local Path' ] = [zipfile_path ]
302
302
return localpath_table
303
303
304
- print ("Inflating..." )
304
+ if verbose : print ("Inflating..." )
305
305
# unzipping the zipfile
306
306
zip_ref = zipfile .ZipFile (zipfile_path , 'r' )
307
307
cutout_files = zip_ref .namelist ()
@@ -477,7 +477,8 @@ def get_surveys(self, coordinates, *, radius="0d"):
477
477
warnings .warn ("Coordinates are not in an available deep field survey." , NoResultsWarning )
478
478
return survey_json
479
479
480
- def download_cutouts (self , coordinates , * , size = 5 , survey = None , cutout_format = "fits" , path = "." , inflate = True , ** img_params ):
480
+ def download_cutouts (self , coordinates , * , size = 5 , survey = None , cutout_format = "fits" , path = "." , inflate = True ,
481
+ verbose = False , ** img_params ):
481
482
"""
482
483
Download cutout FITS/image file(s) around the given coordinates with indicated size.
483
484
@@ -560,7 +561,7 @@ def download_cutouts(self, coordinates, *, size=5, survey=None, cutout_format="f
560
561
localpath_table ['Local Path' ] = [zipfile_path ]
561
562
return localpath_table
562
563
563
- print ("Inflating..." )
564
+ if verbose : print ("Inflating..." )
564
565
# unzipping the zipfile
565
566
zip_ref = zipfile .ZipFile (zipfile_path , 'r' )
566
567
cutout_files = zip_ref .namelist ()
@@ -637,3 +638,164 @@ def get_cutouts(self, coordinates, *, size=5, survey=None):
637
638
638
639
639
640
Zcut = ZcutClass ()
641
+
642
+
643
+ class HapcutClass (MastQueryWithLogin ):
644
+ """
645
+ MAST Hubble Advanced Product (HAP) cutout query class.
646
+
647
+ Class for accessing HAP image cutouts.
648
+ """
649
+
650
+ def __init__ (self ):
651
+
652
+ super ().__init__ ()
653
+
654
+ services = {"astrocut" : {"path" : "astrocut" }}
655
+
656
+ self ._service_api_connection .set_service_params (services , "hapcut" )
657
+
658
+ def download_cutouts (self , coordinates , * , size = 5 , path = "." , inflate = True , verbose = False ):
659
+ """
660
+ Download cutout images around the given coordinates with indicated size.
661
+
662
+ Parameters
663
+ ----------
664
+ coordinates : str or `astropy.coordinates` object
665
+ The target around which to search. It may be specified as a
666
+ string or as the appropriate `astropy.coordinates` object.
667
+ size : int, array-like, `~astropy.units.Quantity`
668
+ Optional, default 5 pixels.
669
+ The size of the cutout array. If ``size`` is a scalar number or
670
+ a scalar `~astropy.units.Quantity`, then a square cutout of ``size``
671
+ will be created. If ``size`` has two elements, they should be in
672
+ ``(ny, nx)`` order. Scalar numbers in ``size`` are assumed to be in
673
+ units of pixels. `~astropy.units.Quantity` objects must be in pixel or
674
+ angular units.
675
+ path : str
676
+ Optional.
677
+ The directory in which the cutouts will be saved.
678
+ Defaults to current directory.
679
+ inflate : bool
680
+ Optional, default True.
681
+ Cutout target pixel files are returned from the server in a zip file,
682
+ by default they will be inflated and the zip will be removed.
683
+ Set inflate to false to stop before the inflate step.
684
+
685
+ Returns
686
+ -------
687
+ response : `~astropy.table.Table`
688
+ """
689
+
690
+ # Get Skycoord object for coordinates/object
691
+ coordinates = parse_input_location (coordinates )
692
+
693
+ # Build initial astrocut request
694
+ astrocut_request = f"astrocut?ra={ coordinates .ra .deg } &dec={ coordinates .dec .deg } "
695
+
696
+ # Add size parameters to request
697
+ size_dict = _parse_cutout_size (size )
698
+ astrocut_request += f"&x={ size_dict ['x' ]} &y={ size_dict ['y' ]} &units={ size_dict ['units' ]} "
699
+
700
+ # Build the URL
701
+ astrocut_url = self ._service_api_connection .REQUEST_URL + astrocut_request
702
+
703
+ # Set up the download path
704
+ path = os .path .join (path , '' )
705
+ zipfile_path = "{}hapcut_{}.zip" .format (path , time .strftime ("%Y%m%d%H%M%S" ))
706
+
707
+ # Download
708
+ self ._download_file (astrocut_url , zipfile_path )
709
+ localpath_table = Table (names = ["Local Path" ], dtype = [str ])
710
+
711
+ # Checking if we got a zip file or a json no results message
712
+ if not zipfile .is_zipfile (zipfile_path ):
713
+ with open (zipfile_path , 'r' ) as FLE :
714
+ response = json .load (FLE )
715
+ warnings .warn (response ['msg' ], NoResultsWarning )
716
+ return localpath_table
717
+
718
+ if not inflate : # not unzipping
719
+ localpath_table ['Local Path' ] = [zipfile_path ]
720
+ return localpath_table
721
+
722
+ if verbose : print ("Inflating..." )
723
+ # unzipping the zipfile
724
+ zip_ref = zipfile .ZipFile (zipfile_path , 'r' )
725
+ cutout_files = zip_ref .namelist ()
726
+ zip_ref .extractall (path , members = cutout_files )
727
+ zip_ref .close ()
728
+ os .remove (zipfile_path )
729
+
730
+ localpath_table ['Local Path' ] = [path + x for x in cutout_files ]
731
+ return localpath_table
732
+
733
+
734
+ def get_cutouts (self , coordinates , * , size = 5 ):
735
+ """
736
+ Get cutout image(s) around the given coordinates with indicated size,
737
+ and return them as a list of `~astropy.io.fits.HDUList` objects.
738
+
739
+ Parameters
740
+ ----------
741
+ coordinates : str or `astropy.coordinates` object
742
+ The target around which to search. It may be specified as a
743
+ string or as the appropriate `astropy.coordinates` object.
744
+ size : int, array-like, `~astropy.units.Quantity`
745
+ Optional, default 5 pixels.
746
+ The size of the cutout array. If ``size`` is a scalar number or
747
+ a scalar `~astropy.units.Quantity`, then a square cutout of ``size``
748
+ will be created. If ``size`` has two elements, they should be in
749
+ ``(ny, nx)`` order. Scalar numbers in ``size`` are assumed to be in
750
+ units of pixels. `~astropy.units.Quantity` objects must be in pixel or
751
+ angular units.
752
+
753
+ Returns
754
+ -------
755
+ response : A list of `~astropy.io.fits.HDUList` objects.
756
+ """
757
+
758
+ # Get Skycoord object for coordinates/object
759
+ coordinates = parse_input_location (coordinates )
760
+
761
+ param_dict = _parse_cutout_size (size )
762
+
763
+ # Need to convert integers from numpy dtypes
764
+ # so we can convert the dictionary into a JSON object
765
+ # in service_request_async(...)
766
+ param_dict ["x" ] = float (param_dict ["x" ])
767
+ param_dict ["y" ] = float (param_dict ["y" ])
768
+
769
+ # Adding RA and DEC to parameters dictionary
770
+ param_dict ["ra" ] = coordinates .ra .deg
771
+ param_dict ["dec" ] = coordinates .dec .deg
772
+
773
+ response = self ._service_api_connection .service_request_async ("astrocut" , param_dict , use_json = True )
774
+ response .raise_for_status () # Raise any errors
775
+
776
+ try :
777
+ ZIPFILE = zipfile .ZipFile (BytesIO (response .content ), 'r' )
778
+ except zipfile .BadZipFile :
779
+ message = response .json ()
780
+ if len (message ['results' ]) == 0 :
781
+ warnings .warn (message ['msg' ], NoResultsWarning )
782
+ return []
783
+ else :
784
+ raise
785
+
786
+ # Open all the contained fits files:
787
+ # Since we cannot seek on a compressed zip file,
788
+ # we have to read the data, wrap it in another BytesIO object,
789
+ # and then open that using fits.open
790
+ cutout_hdus_list = []
791
+ for name in ZIPFILE .namelist ():
792
+ CUTOUT = BytesIO (ZIPFILE .open (name ).read ())
793
+ cutout_hdus_list .append (fits .open (CUTOUT ))
794
+
795
+ # preserve the original filename in the fits object
796
+ cutout_hdus_list [- 1 ].filename = name
797
+
798
+ return cutout_hdus_list
799
+
800
+
801
+ Hapcut = HapcutClass ()
0 commit comments