|
22 | 22 | "Data Release: DP1 <br>\n", |
23 | 23 | "Container Size: large <br>\n", |
24 | 24 | "LSST Science Pipelines version: r29.2.0 <br>\n", |
25 | | - "Last verified to run: 2025-11-20 <br>\n", |
| 25 | + "Last verified to run: 2025-12-15 <br>\n", |
26 | 26 | "Repository: <a href=\"https://github.com/lsst/tutorial-notebooks\">github.com/lsst/tutorial-notebooks</a> <br>" |
27 | 27 | ] |
28 | 28 | }, |
|
98 | 98 | "source": [ |
99 | 99 | "import numpy as np\n", |
100 | 100 | "import matplotlib.pyplot as plt\n", |
101 | | - "import os\n", |
102 | 101 | "\n", |
103 | 102 | "import lsst.afw.display as afwDisplay\n", |
| 103 | + "import lsst.afw.image as afwImage\n", |
104 | 104 | "from lsst.afw.image import ExposureF\n", |
105 | 105 | "from lsst.afw.fits import MemFileManager\n", |
106 | 106 | "\n", |
| 107 | + "\n", |
107 | 108 | "from lsst.rsp.utils import get_pyvo_auth\n", |
108 | 109 | "from lsst.rsp.service import get_siav2_service\n", |
109 | 110 | "\n", |
|
113 | 114 | "\n", |
114 | 115 | "from astropy import units as u\n", |
115 | 116 | "from astropy.coordinates import Angle\n", |
116 | | - "from astropy.time import Time" |
| 117 | + "from astropy.time import Time\n", |
| 118 | + "\n", |
| 119 | + "from astropy.io import fits\n", |
| 120 | + "import io\n" |
117 | 121 | ] |
118 | 122 | }, |
119 | 123 | { |
|
324 | 328 | "id": "d945e191-7ee4-458a-bb0f-fb00cd219e30", |
325 | 329 | "metadata": {}, |
326 | 330 | "source": [ |
327 | | - "Lastly, call the Rubin Image Cutout Service. Three types of cutout services exist: `cutout-sync` which, by default, returns just the image extension of the LSST imaging; `cutout-sync-exposure`, which returns the full set of metadata and image extensions that are contained in the `ExposureF` data type; and `cutout-sync-mask` which contains just the mask extension. This section will demonstrate the use of `cutout-sync-exposure` and Section 4 below will demonstrate the other two. \n", |
| 331 | + "Lastly, call the Rubin Image Cutout Service. This notebook demonstrates two types of cutout services: `cutout-sync` which, by default, returns just the image extension of the LSST imaging; `cutout-sync-exposure`, which returns the full set of metadata and image extensions that are contained in the `ExposureF` data type. This section will demonstrate the use of `cutout-sync-exposure` and Section 4 below will demonstrate the other. \n", |
328 | 332 | "\n", |
329 | 333 | "To use the cutout service in this example, the IVOA procedure `cutout-sync-exposure` is called using `get_adhocservice_by_id`. It is done by feeding the data link created above (called `dl_result`) to `from_resource`. Since the Rubin DP1 imaging is proprietary it is necessary to again provide the authorization for the current RSP session. Do this using the `get_pyvo_auth` function." |
330 | 334 | ] |
|
681 | 685 | "id": "99e75a7a-348e-409e-88f6-871b68a4e9dc", |
682 | 686 | "metadata": {}, |
683 | 687 | "source": [ |
684 | | - "## 4. Other cutout service data types\n", |
685 | | - "\n", |
686 | | - "As mentioned in Section 3, there are three types of cutout services: `cutout-sync-exposure` to return an `ExposureF` type image with all LSST image extensions (demonstrated above); `cutout-sync` which returns just the image extension, and and `cutout-sync-mask` which contains just the mask extension. The latter 2 will be demonstrated below.\n", |
687 | | - "\n", |
688 | | - "### 4.1 Single extension image cutouts\n", |
689 | | - "\n", |
690 | | - "Below demonstrates how to retrieve single extension images using `cutout-sync`." |
691 | | - ] |
692 | | - }, |
693 | | - { |
694 | | - "cell_type": "code", |
695 | | - "execution_count": null, |
696 | | - "id": "c2c8ab4c-cd1d-4ae8-937d-b34a21035e1e", |
697 | | - "metadata": {}, |
698 | | - "outputs": [], |
699 | | - "source": [ |
700 | | - "from astropy.io import fits\n", |
701 | | - "import io\n", |
| 688 | + "## 4. Single extension image cutouts\n", |
702 | 689 | "\n", |
703 | | - "print(results[0])\n", |
704 | | - "datalink_url = results[0].access_url\n", |
705 | | - "dl_result = DatalinkResults.from_result_url(datalink_url,\n", |
706 | | - " session=get_pyvo_auth())\n", |
| 690 | + "As mentioned in Section 3, there are three types of cutout services: `cutout-sync-exposure` to return an `ExposureF` type image with all LSST image extensions (demonstrated above); `cutout-sync` which returns just the image extension. The latter 2 will be demonstrated below.\n", |
707 | 691 | "\n", |
708 | | - "f\"Datalink status: {dl_result.status}. Datalink service url: {datalink_url}\"\n" |
| 692 | + "First, reuse the data link `dl_result` that was defined in Section 3 to define a new cutout, this time using `cutout-sync`. Call this soda query `sq4` to differentiate from the earlier ones. Define the cutout as a square subtended by a circle of radius 0.01 degrees, as done in Section 3.\n" |
709 | 693 | ] |
710 | 694 | }, |
711 | 695 | { |
|
715 | 699 | "metadata": {}, |
716 | 700 | "outputs": [], |
717 | 701 | "source": [ |
718 | | - "\n", |
719 | | - "sq5 = SodaQuery.from_resource(dl_result,\n", |
720 | | - " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", |
721 | | - " session=get_pyvo_auth())\n", |
| 702 | + "sq4 = SodaQuery.from_resource(dl_result,\n", |
| 703 | + " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", |
| 704 | + " session=get_pyvo_auth())\n", |
722 | 705 | "\n", |
723 | 706 | "spherePoint = geom.SpherePoint(target_ra*geom.degrees, target_dec*geom.degrees)\n", |
724 | 707 | "Radius = 0.01 * u.deg\n", |
725 | | - "sq5.circle = (spherePoint.getRa().asDegrees() * u.deg,\n", |
726 | | - " spherePoint.getDec().asDegrees() * u.deg,\n", |
727 | | - " Radius)\n", |
728 | 708 | "\n", |
729 | | - "cutout_bytes = sq5.execute_stream().read()\n", |
730 | | - "sq5.raise_if_error()\n" |
| 709 | + "sq4.circle = (spherePoint.getRa().asDegrees() * u.deg,\n", |
| 710 | + " spherePoint.getDec().asDegrees() * u.deg,\n", |
| 711 | + " Radius)\n", |
| 712 | + "\n", |
| 713 | + "cutout_bytes = sq4.execute_stream().read()\n", |
| 714 | + "sq4.raise_if_error()\n" |
731 | 715 | ] |
732 | 716 | }, |
733 | 717 | { |
734 | | - "cell_type": "code", |
735 | | - "execution_count": null, |
736 | | - "id": "516dbd86-d573-4d81-a017-2ebbce8fb445", |
| 718 | + "cell_type": "markdown", |
| 719 | + "id": "454a017b-df88-48cc-975e-cac4ff3a37b5", |
737 | 720 | "metadata": {}, |
738 | | - "outputs": [], |
739 | 721 | "source": [ |
740 | | - "mem = MemFileManager(len(cutout_bytes))\n", |
741 | | - "mem.setData(cutout_bytes, len(cutout_bytes))\n", |
742 | | - "\n" |
| 722 | + "Receive the cutout into memory, as in Section 3." |
743 | 723 | ] |
744 | 724 | }, |
745 | 725 | { |
746 | 726 | "cell_type": "code", |
747 | 727 | "execution_count": null, |
748 | | - "id": "ed3f7908-a256-42f5-939f-61f38645c7ca", |
| 728 | + "id": "516dbd86-d573-4d81-a017-2ebbce8fb445", |
749 | 729 | "metadata": {}, |
750 | 730 | "outputs": [], |
751 | 731 | "source": [ |
752 | | - "data = mem.getData() # returns `bytes`\n", |
753 | | - "\n", |
754 | | - "# this doesn't work\n", |
755 | | - "import lsst.afw.image as afwImage\n", |
756 | | - "\n", |
757 | | - "#image = afwImage.ImageF(mem)\n" |
| 732 | + "mem = MemFileManager(len(cutout_bytes))\n", |
| 733 | + "mem.setData(cutout_bytes, len(cutout_bytes))\n" |
758 | 734 | ] |
759 | 735 | }, |
760 | 736 | { |
761 | | - "cell_type": "code", |
762 | | - "execution_count": null, |
763 | | - "id": "d23a0397-6500-4e36-b956-7917ed6a7173", |
| 737 | + "cell_type": "markdown", |
| 738 | + "id": "2ae72a88-8002-46b5-8eee-164a2c903314", |
764 | 739 | "metadata": {}, |
765 | | - "outputs": [], |
766 | 740 | "source": [ |
767 | | - "\n", |
768 | | - "#data = mem.getData()\n", |
769 | | - "hdul = fits.open(io.BytesIO(data))\n", |
770 | | - "hdul.info()\n", |
771 | | - "\n", |
772 | | - "image_hdu = hdul[1] # IMAGE extension\n", |
773 | | - "image_data = image_hdu.data # NumPy array\n", |
774 | | - "#image = afwImage.ImageF(image_data)\n", |
775 | | - "image = afwImage.ImageF(image_data.astype(\"float32\"))\n", |
776 | | - "print(type(image_data)) # numpy.ndarray\n", |
777 | | - "print(type(image)) # lsst.afw.image._image.ImageF\n" |
| 741 | + "Use the `getData` method from the `MemFileManager` class to return and store the bytes associated with the cutout. " |
778 | 742 | ] |
779 | 743 | }, |
780 | 744 | { |
781 | 745 | "cell_type": "code", |
782 | 746 | "execution_count": null, |
783 | | - "id": "1aa9009a-b493-41ea-bc3c-e0c79adef913", |
| 747 | + "id": "ed3f7908-a256-42f5-939f-61f38645c7ca", |
784 | 748 | "metadata": {}, |
785 | 749 | "outputs": [], |
786 | 750 | "source": [ |
787 | | - "\n", |
788 | | - "display = afwDisplay.Display()\n", |
789 | | - "display.scale('asinh', 'zscale')\n", |
790 | | - "display.image(image)\n", |
791 | | - "plt.show()" |
| 751 | + "data = mem.getData()\n" |
792 | 752 | ] |
793 | 753 | }, |
794 | 754 | { |
795 | 755 | "cell_type": "markdown", |
796 | | - "id": "918e8779-2939-4978-9ec4-c8a4047f04e9", |
| 756 | + "id": "441a49fb-42be-4f37-853e-141419f1da14", |
797 | 757 | "metadata": {}, |
798 | 758 | "source": [ |
799 | | - "### 4.2 Single extension mask cutouts\n", |
800 | | - "\n", |
801 | | - "Below demonstrates how to retrieve the corresponding mask using `cutout-sync-mask`." |
| 759 | + "Use the astropy.io fits package to access the bytes and store in an HDUList object. Then, the image extension `image_hdu`, and pixel values `image_data` (a numpy array) can be accessed similar to opening a fits file. " |
802 | 760 | ] |
803 | 761 | }, |
804 | 762 | { |
805 | 763 | "cell_type": "code", |
806 | 764 | "execution_count": null, |
807 | | - "id": "a1213ce5-9049-43ce-8032-f1ea2db9c576", |
| 765 | + "id": "d23a0397-6500-4e36-b956-7917ed6a7173", |
808 | 766 | "metadata": {}, |
809 | 767 | "outputs": [], |
810 | 768 | "source": [ |
| 769 | + "hdul = fits.open(io.BytesIO(data))\n", |
| 770 | + "hdul.info()\n", |
811 | 771 | "\n", |
812 | | - "sq5 = SodaQuery.from_resource(dl_result,\n", |
813 | | - " dl_result.get_adhocservice_by_id(\"cutout-sync-maskedimage\"),\n", |
814 | | - " session=get_pyvo_auth())\n", |
815 | | - "\n", |
816 | | - "spherePoint = geom.SpherePoint(target_ra*geom.degrees, target_dec*geom.degrees)\n", |
817 | | - "Radius = 0.01 * u.deg\n", |
818 | | - "sq5.circle = (spherePoint.getRa().asDegrees() * u.deg,\n", |
819 | | - " spherePoint.getDec().asDegrees() * u.deg,\n", |
820 | | - " Radius)\n", |
821 | | - "\n", |
822 | | - "cutout_bytes = sq5.execute_stream().read()\n", |
823 | | - "sq5.raise_if_error()\n" |
| 772 | + "image_hdu = hdul[1]\n", |
| 773 | + "image_data = image_hdu.data\n" |
824 | 774 | ] |
825 | 775 | }, |
826 | 776 | { |
827 | | - "cell_type": "code", |
828 | | - "execution_count": null, |
829 | | - "id": "a2f5ed28-c17d-451b-969c-b7d9186eeb23", |
| 777 | + "cell_type": "markdown", |
| 778 | + "id": "c0eea8e5-ae86-456d-9d67-798557a4a707", |
830 | 779 | "metadata": {}, |
831 | | - "outputs": [], |
832 | 780 | "source": [ |
833 | | - "mem = MemFileManager(len(cutout_bytes))\n", |
834 | | - "mem.setData(cutout_bytes, len(cutout_bytes))\n", |
835 | | - "\n" |
| 781 | + "To enable image display, first store `image_data` as an LSST `ImageF` object." |
836 | 782 | ] |
837 | 783 | }, |
838 | 784 | { |
839 | 785 | "cell_type": "code", |
840 | 786 | "execution_count": null, |
841 | | - "id": "770c6bc2-67f5-4d3f-9d3a-98cd27e28b35", |
| 787 | + "id": "78e1c658-916c-4a73-8c0b-a50d281f4764", |
842 | 788 | "metadata": {}, |
843 | 789 | "outputs": [], |
844 | 790 | "source": [ |
845 | | - "data = mem.getData() # returns `bytes`\n", |
846 | | - "\n", |
847 | | - "# this doesn't work\n", |
848 | | - "import lsst.afw.image as afwImage\n", |
849 | | - "\n", |
850 | | - "#image = afwImage.ImageF(mem)\n" |
| 791 | + "image = afwImage.ImageF(image_data.astype(\"float32\"))\n" |
851 | 792 | ] |
852 | 793 | }, |
853 | 794 | { |
854 | | - "cell_type": "code", |
855 | | - "execution_count": null, |
856 | | - "id": "ba884db3-cd3e-45b9-bba0-ecd98cd95358", |
| 795 | + "cell_type": "markdown", |
| 796 | + "id": "6a19e7cd-4096-44b9-832f-baa6b6c40482", |
857 | 797 | "metadata": {}, |
858 | | - "outputs": [], |
859 | 798 | "source": [ |
860 | | - "\n", |
861 | | - "#data = mem.getData()\n", |
862 | | - "hdul = fits.open(io.BytesIO(data))\n", |
863 | | - "hdul.info()\n", |
864 | | - "\n", |
865 | | - "image_hdu = hdul[2] # IMAGE extension\n", |
866 | | - "image_data = image_hdu.data # NumPy array\n", |
867 | | - "#image = afwImage.ImageF(image_data)\n", |
868 | | - "image = afwImage.ImageF(image_data)#.astype(\"float32\"))\n", |
869 | | - "print(type(image_data)) # numpy.ndarray\n", |
870 | | - "print(type(image)) # lsst.afw.image._image.ImageF\n" |
| 799 | + "Display the image cutout." |
871 | 800 | ] |
872 | 801 | }, |
873 | 802 | { |
874 | 803 | "cell_type": "code", |
875 | 804 | "execution_count": null, |
876 | | - "id": "cceab1fb-7f66-4858-b46f-d71fddb50159", |
| 805 | + "id": "1aa9009a-b493-41ea-bc3c-e0c79adef913", |
877 | 806 | "metadata": {}, |
878 | 807 | "outputs": [], |
879 | 808 | "source": [ |
880 | | - "\n", |
881 | 809 | "display = afwDisplay.Display()\n", |
882 | 810 | "display.scale('asinh', 'zscale')\n", |
883 | 811 | "display.image(image)\n", |
|
904 | 832 | "\n", |
905 | 833 | "</div>\n" |
906 | 834 | ] |
907 | | - }, |
908 | | - { |
909 | | - "cell_type": "code", |
910 | | - "execution_count": null, |
911 | | - "id": "6b611f9f-aaa5-4e2b-b4a5-b7acc6aecbf9", |
912 | | - "metadata": {}, |
913 | | - "outputs": [], |
914 | | - "source": [] |
915 | 835 | } |
916 | 836 | ], |
917 | 837 | "metadata": { |
|
0 commit comments