From 89252d89494c4997f77a083d599dfa770811f692 Mon Sep 17 00:00:00 2001 From: jeffcarlin Date: Tue, 5 May 2026 20:12:41 +0000 Subject: [PATCH 1/4] Add full version of 101_1 alerts NB --- ...101_1_Alert_retrieval_service_Herald.ipynb | 150 ++++++++++++++++-- 1 file changed, 133 insertions(+), 17 deletions(-) diff --git a/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service_Herald.ipynb b/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service_Herald.ipynb index 00f61441..03daa097 100644 --- a/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service_Herald.ipynb +++ b/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service_Herald.ipynb @@ -22,7 +22,7 @@ "Data Release: [Prompt Products](https://prompt-products.lsst.io/)\\\n", "Container Size: Large\\\n", "LSST Science Pipelines version: r29.2.0\\\n", - "Last verified to run: 2026-04-24\\\n", + "Last verified to run: 2026-05-04\\\n", "Repository: [github.com/lsst/tutorial-notebooks](https://github.com/lsst/tutorial-notebooks)\\\n", "DOI: [10.11578/rubin/dc.20250909.20](https://doi.org/10.11578/rubin/dc.20250909.20)" ] @@ -59,10 +59,10 @@ "**Alert packets** are files of measurements for sources detected in difference images that are streamed to brokers within a few minutes of image acquisition.\n", "Alerts are a Prompt Product, and are the result of Rubin's Difference Image Analysis (DIA) and Alert Production (AP) pipelines.\n", "\n", - "**Brokers** are the recommended way to do time-domain science with alerts because their functionality includes, e.g., filtering, cross-match, classification, and users can explore and retrieve scientifically-relevant subsets via their web-based user interfaces or via API clients.\n", + "**Brokers** are the recommended way to do time-domain science with alerts because their functionality includes, e.g., filtering, cross-match, and classification, and users can explore and retrieve scientifically-relevant subsets via their web-based user interfaces or API clients.\n", "\n", "**Why use the RSP's alert retrieval service, Herald?** \\\n", - "When only the contents of a single alert packet are desired, and the alert ID is known.\n", + "Herald is useful when only the contents of a single alert packet are desired, and the alert ID is known.\n", "Otherwise, brokers are the best way to do real-time science with the alerts, and scientific analyses on longer timescales (days to weeks) can use the other Prompt Products (queryable databases, images).\n", "\n", "**Additional resources:**\n", @@ -302,7 +302,7 @@ "source": [ "#### 2.1.2. Lightcurve\n", "\n", - "Extract the band, MJD, and forced PSF difference-image flux from the alert record as `numpy` arrays, and plot the lightcurve." + "Extract the band, MJD, and forced PSF difference-image fluxes from the alert record as `numpy` arrays, and plot the lightcurve." ] }, { @@ -456,7 +456,7 @@ } }, "source": [ - "Avro schemas are written in JSON, so convert in order to explore." + "Avro schemas are written in JSON, so use the `response.json()` method to convert to a Python dict in order to explore." ] }, { @@ -474,7 +474,7 @@ "id": "633b43f1-db19-444b-95b4-19e14b84379a", "metadata": {}, "source": [ - "This converts to JSON but use native or something else in the Avro section " + "Print some fields from the schema." ] }, { @@ -597,7 +597,7 @@ "id": "5da256b2-fe69-4dae-b3e7-ba1d5472c4fa", "metadata": {}, "source": [ - "> **Figure 3:** The science, template, and difference-image stamps." + "> **Figure 3:** The difference-image, science, and template stamps." ] }, { @@ -625,7 +625,7 @@ "source": [ "## 3. JSON format\n", "\n", - "The JSON response is the full deserialized alert record." + "The JSON response is the full deserialized alert record. Request the JSON formatted response by using the `RESPONSEFORMAT` keyword." ] }, { @@ -719,7 +719,7 @@ "id": "13083cd9-5ee4-40f8-bca1-ef31c1762f72", "metadata": {}, "source": [ - "Option to display the stamps. The code is very similar to that used for the Avro packets, except in the JSON formatted packet the image stamps are base64-encoded bytes. They need to be first decoded with `base64.b64decode` then read as bytes with `io.BytesIO` by `fits.open`." + "Option to display the stamps. The code is very similar to that used for the Avro packets, except in the JSON formatted packet the image stamps are base64-encoded bytes. They need to be first decoded with `base64.b64decode` then read as bytes with `io.BytesIO` by `fits.open`. Note also that the stamps are in a different order than in the Avro packets." ] }, { @@ -732,7 +732,7 @@ "# stamps = [base64.b64decode(record.get(\"cutoutDifference\")),\n", "# base64.b64decode(record.get(\"cutoutScience\")),\n", "# base64.b64decode(record.get(\"cutoutTemplate\"))]\n", - "# stamp_names = ['Science', 'Template', 'Difference']\n", + "# stamp_names = ['Difference', 'Science', 'Template', ]\n", "\n", "# fig, ax = plt.subplots(1, 3, figsize=(9, 3))\n", "# for s, (stamp, name) in enumerate(zip(stamps, stamp_names)):\n", @@ -844,7 +844,24 @@ "outputs": [], "source": [ "hdu = hdul['PRIMARY']\n", - "hdu.header\n", + "hdu.header" + ] + }, + { + "cell_type": "markdown", + "id": "5ba9785f-a260-4bca-ba22-e762cee48762", + "metadata": {}, + "source": [ + "Clean up." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8985dd43-b8c5-4a85-8f99-8c8444f5ff19", + "metadata": {}, + "outputs": [], + "source": [ "del hdu" ] }, @@ -932,7 +949,7 @@ "# mew=1, alpha=0.7, mec=filter_colors[filt], color='None', label=filt)\n", "# del fx\n", "# plt.xlabel('MJD')\n", - "# plt.ylabel('forced difference-image flux [nJy]')\n", + "# plt.ylabel('difference-image PSF flux [nJy]')\n", "# plt.legend(bbox_to_anchor=(1.05, 1), handletextpad=0, loc='upper left')\n", "# plt.tight_layout()\n", "# plt.show()\n", @@ -945,12 +962,80 @@ "id": "88fe362b-74f3-47e2-9e12-e90329c4cfce", "metadata": {}, "source": [ - "**FORCEDPHOT** \\\n", - "Contains the forced photometry history.\n", + "**FORCEDPHOT**\n", + "\n", + "The `FORCEDPHOT` extension contains forced measurement data on all previous visits at the position of the `diaSource` (the lightcurve). This includes measurements on the difference images and the science images.\n", + "\n", + "Option to extract the `diaSource` data and plot the forced photometry lightcurve." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f14e6bb2-6daf-425f-acfb-08d23044fedd", + "metadata": {}, + "outputs": [], + "source": [ + "# hdu = hdul['FORCEDPHOT']\n", + "# data = hdu.data\n", + "# fig = plt.figure(figsize=(6, 3))\n", + "# for f, filt in enumerate(filter_names):\n", + "# fx = np.where(data['band'] == filt)[0]\n", + "# if len(fx) > 0:\n", + "# plt.plot(data['midpointMjdTai'][fx], data['psfFlux'][fx], filter_symbols[filt], ms=5,\n", + "# mew=1, alpha=0.7, mec=filter_colors[filt], color='None', label=filt)\n", + "# del fx\n", + "# plt.xlabel('MJD')\n", + "# plt.ylabel('forced difference-image flux [nJy]')\n", + "# plt.legend(bbox_to_anchor=(1.05, 1), handletextpad=0, loc='upper left')\n", + "# plt.tight_layout()\n", + "# plt.show()\n", + "# del data\n", + "# del hdu" + ] + }, + { + "cell_type": "markdown", + "id": "d8f5c41d-3ade-48ca-acec-f50c6f6ea080", + "metadata": {}, + "source": [ + "**SSSOURCE**\n", "\n", - "**SSSOURCE** \\\n", - "For alerts associated with moving objects.\n", - "Contains the LSST-computed per-source instantaneous quantities at the time of observation (e.g., heliocentric and topocentric positions and velocities)." + "The `SSSOURCE` extension contains the LSST-computed per-source instantaneous quantities at the time of observation (e.g., heliocentric and topocentric positions and velocities) for alerts associated with moving objects (i.e., Solar System objects).\n", + "\n", + "Using an ID of a known Solar System object (SSO), retrieve the `SSSOURCE` information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5521e26b-372f-4bb3-b7b4-0b8dff89b19c", + "metadata": {}, + "outputs": [], + "source": [ + "sso_alert_id = \"170059294376985743\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2591fd5-d81f-4b86-a63d-bc038e9fedc9", + "metadata": {}, + "outputs": [], + "source": [ + "sso_response = await client.get(url, params={\"ID\": sso_alert_id, \"RESPONSEFORMAT\": \"fits\"})\n", + "sso_response.raise_for_status()\n", + "sso_hdul = fits.open(io.BytesIO(sso_response.content))\n", + "for hdu in sso_hdul:\n", + " print(hdu.name)" + ] + }, + { + "cell_type": "markdown", + "id": "08ccc9f5-c81c-4a30-9370-c31875505774", + "metadata": {}, + "source": [ + "Note that the header cards are the same for all alerts. However, this alert will have data in the `SSSOURCE` extension. Extract that extension, and examine the `ssObjectId` of the alert." ] }, { @@ -959,6 +1044,37 @@ "id": "71595613-25b8-45c3-a730-b24e215a5284", "metadata": {}, "outputs": [], + "source": [ + "hdu = sso_hdul['SSSOURCE']\n", + "sso_data = hdu.data\n", + "print(sso_data['ssObjectId'])" + ] + }, + { + "cell_type": "markdown", + "id": "409d9c8b-b503-4b6c-8691-a57a40d0e915", + "metadata": {}, + "source": [ + "Option to list the names of all the columns in `SSSOURCE`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "804f1a16-59bc-444c-9760-d01ea196d349", + "metadata": {}, + "outputs": [], + "source": [ + "# for col in sso_hdul['SSSOURCE'].columns:\n", + "# print(col)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfda84a2-1323-4625-9abd-de3ddf9ae8d9", + "metadata": {}, + "outputs": [], "source": [] } ], From 4e0f66a9ded287afd65c59380cd8d9177723f926 Mon Sep 17 00:00:00 2001 From: jeffcarlin Date: Tue, 5 May 2026 20:49:53 +0000 Subject: [PATCH 2/4] Add full version of 201_1 alerts NB --- .../201_Alerts/201_1_Alert_packets.ipynb | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb b/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb index 33224bb5..02cf136f 100644 --- a/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb +++ b/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb @@ -31,7 +31,7 @@ "Data Release: [Prompt Products](https://prompt-products.lsst.io/)\\\n", "Container Size: Large\\\n", "LSST Science Pipelines version: r29.2.0\\\n", - "Last verified to run: 2026-04-24\\\n", + "Last verified to run: 2026-05-05\\\n", "Repository: [github.com/lsst/tutorial-notebooks](https://github.com/lsst/tutorial-notebooks)\\\n", "DOI: [10.11578/rubin/dc.20250909.20](https://doi.org/10.11578/rubin/dc.20250909.20)" ] @@ -80,8 +80,8 @@ "4. Image cutouts (stamps) from the science, template, and difference images, for the triggering `diaSource`.\n", "\n", "**How do alerts relate to Rubin's other Prompt Products?** \\\n", - "The data in the alert packets will also stored in a queryable database, the Prompt Products Database (PPDB), which will update on a ~24-hour timescale and will available via the Rubin Science Platform (RSP).\n", - "The contents of the PPDB are public but RSP access is not (unlike broker access).\n", + "The data in the alert packets will also be stored in a queryable database, the Prompt Products Database (PPDB), which will update on a ~24-hour timescale and will be available via the Rubin Science Platform (RSP).\n", + "The *contents* of the PPDB are public but RSP access is not (unlike broker access).\n", "The processed visit images and difference images become available via the RSP after an 80-hour embargo, and are subject to the two-year proprietary period. (See the [Rubin Data Policy](https://rubinobservatory.org/for-scientists/data-products/data-policy).)\n", "\n", "**Additional resources:**\n", @@ -234,8 +234,8 @@ "Other formats (JSON, FITS) are possible, as demonstrated in the 100-level tutorial on the alert retrieval service.\n", "\n", "Pass the `url` to the `client` along with the `alert_id`.\n", - "Use the `await` command to pause execute of the cell's code until a response is received, then show the `response`.\n", - "Retreive the alert for the `snia_alert_id`." + "Use the `await` command to pause execution of the cell's code until a response is received, then show the `response`.\n", + "Retrieve the alert for the `snia_alert_id`." ] }, { @@ -332,7 +332,7 @@ "source": [ "### 2.2. Packet schema\n", "\n", - "The `fastavro.reader` used above reads the embedded schema automatically\n", + "The `fastavro.reader` used above reads the embedded schema automatically.\n", "\n", "Extract the schema, and show that the keys and fields are the same for each (but for triggering `diaSources` that are associated with a `diaObject` instead of a `ssObject`, the fields `ssSource` and `mpc_orbits` won't be populated)." ] @@ -493,7 +493,7 @@ "id": "aae8cf9b-c0ab-40d3-95f4-dacdc5a9ebe7", "metadata": {}, "source": [ - "Option to print the keys of `diaSource`, which are the same all objects." + "Option to print the keys of `diaSource`, which are the same for all objects." ] }, { @@ -516,7 +516,7 @@ "* `band`: LSST filter of the observation, one of: $ugrizy$.\n", "* `midpointMjdTai`: The MJD at the midpoint of the exposure.\n", "* `psfFlux`, `psfFluxErr`: The PSF flux and its error, measured on the difference image, in nJy.\n", - "* `scienceFlux`, `scienceFluxErr`: This PSF flux and its error, measured on the science image, in nJy.\n", + "* `scienceFlux`, `scienceFluxErr`: The PSF flux and its error, measured on the science image, in nJy.\n", "\n", "> **Warning:** while the science flux is useful for variable stars, for supernovae it is typically contaminated by host galaxy light and is inappropriate for use in a lightcurve.\n", "\n", @@ -767,11 +767,11 @@ "\n", "* `ssObjectid`: Unique ID in the `ssObject` table.\n", "* `phaseAngle`: Phase angle between the Sun, object, and observer, in degrees.\n", - "* `eclBeta`, `eclLambda`: The ecliptic latitude and logintude, in degrees.\n", + "* `eclBeta`, `eclLambda`: The ecliptic latitude and longitude, in degrees.\n", "* `elongation`: Solar elongation, in degrees.\n", "* `ephVmag`: Predicted magnitude in V band.\n", "\n", - "The heliocentric and topocentric positions and velocities (`helio_` and `topo_` `x`, `y`, `z`, `vx`, `vy`, `vz`) and also included, among other parameters.\n", + "The heliocentric and topocentric positions and velocities (`helio_` and `topo_` `x`, `y`, `z`, `vx`, `vy`, `vz`) are also included, among other parameters.\n", "\n", "Print a few of the key column values." ] @@ -929,7 +929,7 @@ "id": "ea1a9163-5706-4a55-ae75-da94df78f3a1", "metadata": {}, "source": [ - "Plot separately the lightcurves using the detections (plus the triggering detection), and using the force photometry.\n", + "Plot separately the lightcurves using the detections (plus the triggering detection), and using the forced photometry.\n", "\n", "The fluxes in the g, r, and i bands overlap, so impose a flux offset by filter when plotting." ] @@ -1114,7 +1114,7 @@ "id": "aa4d7992-b4f8-4725-bd8a-e01a90b2badb", "metadata": {}, "source": [ - "> **Figure 2:** Image stamps from the SNIa alert packet. The literature coordinats of the SNIa are marked with a yellow circle, and the north direction indicated with a cyan line." + "> **Figure 2:** Image stamps from the SNIa alert packet. The literature coordinates of the SNIa are marked with a yellow circle, and the north direction indicated with a cyan line." ] }, { From 6aee6c7e487508c694be339d3b640de265b1e61c Mon Sep 17 00:00:00 2001 From: jeffcarlin Date: Thu, 28 May 2026 01:02:45 +0000 Subject: [PATCH 3/4] Remove afwImage and afwDisplay usage, refs to Herald --- ...nb => 101_1_Alert_retrieval_service.ipynb} | 166 ++++++++---------- .../201_Alerts/201_1_Alert_packets.ipynb | 123 ++++++------- 2 files changed, 124 insertions(+), 165 deletions(-) rename Prompt/100_How_to_use_RSP_tools/101_Alert_archive/{101_1_Alert_retrieval_service_Herald.ipynb => 101_1_Alert_retrieval_service.ipynb} (98%) diff --git a/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service_Herald.ipynb b/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service.ipynb similarity index 98% rename from Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service_Herald.ipynb rename to Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service.ipynb index 03daa097..a65c8152 100644 --- a/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service_Herald.ipynb +++ b/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service.ipynb @@ -10,7 +10,7 @@ "id": "b5c1694b-bfcb-48d8-8bab-4e5e7b4ea55f", "metadata": {}, "source": [ - "# 101.1. Alert retrieval service (Herald)\n", + "# 101.1. Alert retrieval service\n", "\n", "
\n", "\n", @@ -22,7 +22,7 @@ "Data Release: [Prompt Products](https://prompt-products.lsst.io/)\\\n", "Container Size: Large\\\n", "LSST Science Pipelines version: r29.2.0\\\n", - "Last verified to run: 2026-05-04\\\n", + "Last verified to run: 2026-05-27\\\n", "Repository: [github.com/lsst/tutorial-notebooks](https://github.com/lsst/tutorial-notebooks)\\\n", "DOI: [10.11578/rubin/dc.20250909.20](https://doi.org/10.11578/rubin/dc.20250909.20)" ] @@ -32,7 +32,7 @@ "id": "dcd70a28-00af-41c5-b81a-ee1da3024db8", "metadata": {}, "source": [ - "**Learning objective:** How to obtain single alert packets from the RSP's alert retrieval service, Herald.\n", + "**Learning objective:** How to obtain single alert packets from the RSP's alert retrieval service.\n", "\n", "**LSST data products:** Alert packets.\n", "\n", @@ -54,15 +54,15 @@ "source": [ "## 1. Introduction\n", "\n", - "The RSP's alert retrieval service, Herald, enables the contents of single alert packets to be retrieved by alert ID number, in one of three formats: Avro, JSON, or FITS. See also the technical note \"Design of an Alert Retrieval Service in the RSP\" ([SQR-114](https://sqr-114.lsst.io/)).\n", + "The RSP's alert retrieval service enables the contents of single alert packets to be retrieved by alert ID number, in one of three formats: Avro, JSON, or FITS. See also the technical note \"Design of an Alert Retrieval Service in the RSP\" ([SQR-114](https://sqr-114.lsst.io/)).\n", "\n", "**Alert packets** are files of measurements for sources detected in difference images that are streamed to brokers within a few minutes of image acquisition.\n", "Alerts are a Prompt Product, and are the result of Rubin's Difference Image Analysis (DIA) and Alert Production (AP) pipelines.\n", "\n", "**Brokers** are the recommended way to do time-domain science with alerts because their functionality includes, e.g., filtering, cross-match, and classification, and users can explore and retrieve scientifically-relevant subsets via their web-based user interfaces or API clients.\n", "\n", - "**Why use the RSP's alert retrieval service, Herald?** \\\n", - "Herald is useful when only the contents of a single alert packet are desired, and the alert ID is known.\n", + "**Why use the RSP's alert retrieval service?** \\\n", + "The alert retrieval service is useful when only the contents of a single alert packet are desired, and the alert ID is known.\n", "Otherwise, brokers are the best way to do real-time science with the alerts, and scientific analyses on longer timescales (days to weeks) can use the other Prompt Products (queryable databases, images).\n", "\n", "**Additional resources:**\n", @@ -70,7 +70,7 @@ "* [Prompt Products documentation](https://prompt-products.lsst.io/).\n", "* [Learn more about the LSST alert brokers](https://rubinobservatory.org/for-scientists/data-products/alerts-and-brokers).\n", "\n", - "**This tutorial** focuses on how Herald works, and options for packet retrieval formats (e.g., FITS, JSON, schema-only, cutouts-only).\n", + "**This tutorial** focuses on how the alert retrieval service works, and options for packet retrieval formats (e.g., FITS, JSON, schema-only, cutouts-only).\n", "\n", "**Related tutorials:** The 200-level tutorial on alert packets focuses on the details of the packets' schema and data contents, and how packets for static-sky and moving objects differ." ] @@ -82,8 +82,8 @@ "source": [ "### 1.1. Import packages\n", "\n", - "Import the `fastavro` package for reading alerts from Herald in the default Avro format. Import the `base64` package for reading image stamps in the JSON format.\n", - "Import the `RSPClient` and `get_service_url` in order to access Herald.\n", + "Import the `fastavro` package for reading alerts in the default Avro format. Import the `base64` package for reading image stamps in the JSON format.\n", + "Import the `RSPClient` and `get_service_url` in order to access the alert retrieval service.\n", "Also import a range of other plotting and analyis packages." ] }, @@ -98,12 +98,14 @@ "import base64\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "import pandas as pd\n", "import io\n", "from astropy.io import fits\n", + "from astropy.nddata import CCDData\n", + "from astropy.visualization import (MinMaxInterval, LinearStretch,\n", + " ImageNormalize)\n", "\n", "from lsst.rsp import RSPClient, get_service_url\n", - "import lsst.afw.display as afwDisplay\n", - "import lsst.afw.image as afwImage\n", "from lsst.utils.plotting import (get_multiband_plot_colors,\n", " get_multiband_plot_symbols)" ] @@ -115,7 +117,7 @@ "source": [ "### 1.2. Define parameters and functions\n", "\n", - "Establish the connection to Herald by getting the `url` for the alerts retrieval service and instantiating the `RSPClient`." + "Establish the connection to the alert retrieval service by getting the `url` for the service and instantiating the `RSPClient`." ] }, { @@ -129,24 +131,6 @@ "client = RSPClient(\"\")" ] }, - { - "cell_type": "markdown", - "id": "09e530e3-1b9e-437c-ae50-94c56513ec8a", - "metadata": {}, - "source": [ - "Set the `afwDisplay` backend to `matplotlib`, to be used when displaying the image stamps." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9e321748-27ba-4987-bd22-0cc7c250b0f4", - "metadata": {}, - "outputs": [], - "source": [ - "afwDisplay.setDefaultBackend(\"matplotlib\")" - ] - }, { "cell_type": "markdown", "id": "53d0a4a0-0fd5-4b7d-8b47-4507e713da5c", @@ -192,7 +176,7 @@ "source": [ "## 2. Avro format\n", "\n", - "An Avro Object Container File (OCF) is the default response format from Herald.\n", + "An Avro Object Container File (OCF) is the default response format from the alert retrieval service and has the same format as the originally-transmitted alert packet.\n", "\n", "### 2.1. Full packet\n", "\n", @@ -302,41 +286,42 @@ "source": [ "#### 2.1.2. Lightcurve\n", "\n", - "Extract the band, MJD, and forced PSF difference-image fluxes from the alert record as `numpy` arrays, and plot the lightcurve." + "Extract the band, MJD, and PSF difference-image fluxes from the alert record as `numpy` arrays, and plot the lightcurve.\n", + "\n", + "Begin by extracting the `diaSource` and previous diaSource (`prvDiaSources`) measurements to pandas dataframes, then concatenate them into a single dataframe." ] }, { "cell_type": "code", "execution_count": null, - "id": "ba74bfb8-9880-4ef2-842b-b062b054d4a5", + "id": "140c18b7-bbfe-4663-8564-735644c75dbf", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.DataFrame(record['diaSource'], index=[0])\n", + "df_prv = pd.DataFrame(record['prvDiaSources'])\n", + "df_all = pd.concat([df, df_prv], ignore_index=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9013c2b-5612-4c9e-a6ce-351ee0de3501", "metadata": {}, "outputs": [], "source": [ - "band = []\n", - "mjd = []\n", - "flux = []\n", - "for pdfs in record['prvDiaForcedSources']:\n", - " band.append(pdfs['band'])\n", - " mjd.append(pdfs['midpointMjdTai'])\n", - " flux.append(pdfs['psfFlux'])\n", - "lc_band = np.asarray(band, dtype='str')\n", - "lc_mjd = np.asarray(mjd, dtype='float')\n", - "lc_flux = np.asarray(flux, dtype='float')\n", - "del band, mjd, flux\n", - "\n", "fig = plt.figure(figsize=(6, 3))\n", "for f, filt in enumerate(filter_names):\n", - " fx = np.where(lc_band == filt)[0]\n", - " if len(fx) > 0:\n", - " plt.plot(lc_mjd[fx], lc_flux[fx], filter_symbols[filt], ms=5, mew=1,\n", + " df_pick_band = df_all.loc[df_all['band'] == filt]\n", + " if len(df_pick_band) > 0:\n", + " plt.plot(df_pick_band['midpointMjdTai'], df_pick_band['psfFlux'], filter_symbols[filt], ms=5, mew=1,\n", " alpha=0.7, mec=filter_colors[filt], color='None', label=filt)\n", - " del fx\n", + "\n", "plt.xlabel('MJD')\n", - "plt.ylabel('forced difference-image flux [nJy]')\n", + "plt.ylabel('diaSource PSF flux [nJy]')\n", "plt.legend(bbox_to_anchor=(1.05, 1), handletextpad=0, loc='upper left')\n", "plt.tight_layout()\n", - "plt.show()\n", - "del lc_band, lc_mjd, lc_flux" + "plt.show()" ] }, { @@ -344,7 +329,7 @@ "id": "dc1ee5e6-6592-46e2-8147-2f0e69e0442c", "metadata": {}, "source": [ - "> **Figure 1:** The forced PSF difference-image flux lightcurve." + "> **Figure 1:** The PSF difference-image flux lightcurve." ] }, { @@ -360,7 +345,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a2bf9eac-fc48-4ff8-a2da-b91269b3ef90", + "id": "c51bb65a-7214-4f51-92f7-b3df7307b551", "metadata": {}, "outputs": [], "source": [ @@ -373,11 +358,12 @@ "for s, (stamp, name) in enumerate(zip(stamps, stamp_names)):\n", " hdul = fits.HDUList.fromstring(stamp)\n", " data = hdul[0].data\n", - " image = afwImage.ImageF(data.astype(\"float32\"))\n", + " image = CCDData(data.astype(\"float32\"), unit='nJy')\n", + " norm = ImageNormalize(image, interval=MinMaxInterval(),\n", + " stretch=LinearStretch())\n", " plt.sca(ax[s])\n", - " display = afwDisplay.Display(frame=fig)\n", - " display.scale(\"linear\", \"minmax\")\n", - " display.image(image)\n", + " plt.imshow(image, origin='lower', norm=norm, cmap='gray')\n", + " plt.colorbar()\n", " ax[s].set_title(name)\n", "plt.tight_layout()\n", "plt.show()" @@ -539,7 +525,7 @@ "source": [ "### 2.3. Stamps only\n", "\n", - "If only the image stamps (cutouts) from an alert are desired, have Herald only return the images in the response." + "If only the image stamps (cutouts) from an alert are desired, have the alert retrieval service only return the images in the response." ] }, { @@ -583,11 +569,13 @@ "if len(stamps) == 1:\n", " axes = [axes]\n", "for ax, name in zip(axes, stamp_names):\n", - " image = afwImage.ImageF(stamps[name].data.astype(\"float32\"))\n", + " image = CCDData(stamps[name].data.astype(\"float32\"), unit='nJy')\n", + " norm = ImageNormalize(image, interval=MinMaxInterval(),\n", + " stretch=LinearStretch())\n", " plt.sca(ax)\n", - " display = afwDisplay.Display(frame=fig)\n", - " display.scale('linear', 'zscale')\n", - " display.mtv(image, title=name)\n", + " plt.imshow(image, origin='lower', norm=norm, cmap='gray')\n", + " plt.title(name)\n", + " plt.colorbar()\n", "plt.tight_layout()\n", "plt.show()" ] @@ -683,35 +671,26 @@ { "cell_type": "code", "execution_count": null, - "id": "15235167-1a46-4347-8575-d66532eb3aa9", + "id": "f251faae-1eb2-45c3-900c-59f02d0003fd", "metadata": {}, "outputs": [], "source": [ - "# band = []\n", - "# mjd = []\n", - "# flux = []\n", - "# for pdfs in record['prvDiaForcedSources']:\n", - "# band.append(pdfs['band'])\n", - "# mjd.append(pdfs['midpointMjdTai'])\n", - "# flux.append(pdfs['psfFlux'])\n", - "# lc_band = np.asarray(band, dtype='str')\n", - "# lc_mjd = np.asarray(mjd, dtype='float')\n", - "# lc_flux = np.asarray(flux, dtype='float')\n", - "# del band, mjd, flux\n", - "\n", + "# df = pd.DataFrame(record['diaSource'], index=[0])\n", + "# df_prv = pd.DataFrame(record['prvDiaSources'])\n", + "# df_all = pd.concat([df, df_prv], ignore_index=True)\n", + "# \n", "# fig = plt.figure(figsize=(6, 3))\n", "# for f, filt in enumerate(filter_names):\n", - "# fx = np.where(lc_band == filt)[0]\n", - "# if len(fx) > 0:\n", - "# plt.plot(lc_mjd[fx], lc_flux[fx], filter_symbols[filt], ms=5, mew=1,\n", - "# alpha=0.7, mec=filter_colors[filt], color='None', label=filt)\n", - "# del fx\n", + "# df_pick_band = df_all.loc[df_all['band'] == filt]\n", + "# if len(df_pick_band) > 0:\n", + "# plt.plot(df_pick_band['midpointMjdTai'], df_pick_band['psfFlux'], filter_symbols[filt], ms=5, mew=1,\n", + "# alpha=0.7, mec=filter_colors[filt], color='None', label=filt)\n", + "# \n", "# plt.xlabel('MJD')\n", - "# plt.ylabel('forced difference-image flux [nJy]')\n", + "# plt.ylabel('diaSource PSF flux [nJy]')\n", "# plt.legend(bbox_to_anchor=(1.05, 1), handletextpad=0, loc='upper left')\n", "# plt.tight_layout()\n", - "# plt.show()\n", - "# del lc_band, lc_mjd, lc_flux" + "# plt.show()" ] }, { @@ -738,11 +717,12 @@ "# for s, (stamp, name) in enumerate(zip(stamps, stamp_names)):\n", "# hdul = fits.open(io.BytesIO(stamp))\n", "# data = hdul[0].data\n", - "# image = afwImage.ImageF(data.astype(\"float32\"))\n", + "# image = CCDData(data.astype(\"float32\"), unit='nJy')\n", + "# norm = ImageNormalize(image, interval=MinMaxInterval(),\n", + "# stretch=LinearStretch())\n", "# plt.sca(ax[s])\n", - "# display = afwDisplay.Display(frame=fig)\n", - "# display.scale(\"linear\", \"minmax\")\n", - "# display.image(image)\n", + "# plt.imshow(image, origin='lower', norm=norm, cmap='gray')\n", + "# plt.colorbar()\n", "# ax[s].set_title(name)\n", "# plt.tight_layout()\n", "# plt.show()\n", @@ -883,13 +863,13 @@ "source": [ "# fig, ax = plt.subplots(1, 3, figsize=(9, 3))\n", "# for i, ext in enumerate([\"SCIENCE\", \"TEMPLATE\", \"DIFFIM\"]):\n", - "# image = afwImage.ImageF(hdul[ext].data.astype(\"float32\"))\n", + "# image = CCDData(hdul[ext].data.astype(\"float32\"), unit='nJy')\n", + "# norm = ImageNormalize(image, interval=MinMaxInterval(),\n", + "# stretch=LinearStretch())\n", "# plt.sca(ax[i])\n", - "# display = afwDisplay.Display(frame=fig)\n", - "# display.scale(\"asinh\", \"zscale\")\n", - "# display.image(image)\n", + "# plt.imshow(image, origin='lower', norm=norm, cmap='gray')\n", + "# plt.colorbar()\n", "# ax[i].set_title(ext)\n", - "# del image\n", "# plt.tight_layout()\n", "# plt.show()" ] diff --git a/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb b/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb index 02cf136f..8f00060b 100644 --- a/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb +++ b/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb @@ -31,7 +31,7 @@ "Data Release: [Prompt Products](https://prompt-products.lsst.io/)\\\n", "Container Size: Large\\\n", "LSST Science Pipelines version: r29.2.0\\\n", - "Last verified to run: 2026-05-05\\\n", + "Last verified to run: 2026-05-27\\\n", "Repository: [github.com/lsst/tutorial-notebooks](https://github.com/lsst/tutorial-notebooks)\\\n", "DOI: [10.11578/rubin/dc.20250909.20](https://doi.org/10.11578/rubin/dc.20250909.20)" ] @@ -67,13 +67,14 @@ "Alerts are streamed to **brokers** within a few minutes of the acquisition of every new image to enable real-time analysis and spectroscopic follow-up, and brokers are the recommended way to do time-domain science with alerts.\n", "Alerts are world public and have no proprietary period.\n", "\n", - "**Alert packets are generated by the Prompt processing pipeline**, which runs **Difference Image Analysis (DIA)** for each new exposure, provided a template image exists for that sky location.\n", + "**Alert packets are generated by the Alert Production pipeline**, which runs **Difference Image Analysis (DIA)** for each new exposure, provided a template image exists for that sky location.\n", "The template image is subtracted from the new processed visit image (the 'science' image) to produce a difference image.\n", "Source detection is run on the difference image, and every source (positive or negative) detected with signal-to-noise ratio $\\geq 5$ becomes a `diaSource`.\n", - "Every `diaSource` is associated with either a `diaObject` (static sky coordinates) or an `mpc_orbit` (moving object in the solar system with a known orbit).\n", + "Every `diaSource` is associated with either a `diaObject` (static sky coordinates) or an `ssObject` (Solar System object).\n", "One alert is created per `diaSource`.\n", "\n", - "**What is included in an alert packet?**\n", + "**What is included in an alert packet?** \\\n", + "Alert packets include the following information, and much more. See [the Prompt Products documentation](https://prompt-products.lsst.io/products/alerts/index.html#contents) for a more complete list.\n", "1. The triggering `diaSource` record, which includes photometric and astrometric measurements and metadata.\n", "2. The associated `diaObject` or `mpc_orbit` record, which includes derived properties for the object.\n", "3. Previous `diaSource` records associated with the `diaObject` from the last 12 months, maximum.\n", @@ -91,7 +92,7 @@ "\n", "**This tutorial** focuses on the details of the packets' schema and data contents, and how packets for static-sky and moving objects differ.\n", "\n", - "**Related tutorials:** The 100-level tutorial on the alert retrieval service, Herald, focuses on how the service works, and options for packet retrieval formats (e.g., FITS, JSON, schema-only, cutouts-only)." + "**Related tutorials:** The 100-level tutorial on the alert retrieval service focuses on how the service works, and options for packet retrieval formats (e.g., FITS, JSON, schema-only, cutouts-only)." ] }, { @@ -101,8 +102,8 @@ "source": [ "### 1.1. Import packages\n", "\n", - "Import the `fastavro` package for reading alerts from Herald in the default Avro format.\n", - "Import the `RSPClient` and `get_service_url` in order to access Herald.\n", + "Import the `fastavro` package for reading alerts from the alert retrieval service in the default Avro format.\n", + "Import the `RSPClient` and `get_service_url` in order to access the alert retrieval service.\n", "Also import a range of other plotting and analyis packages." ] }, @@ -116,15 +117,18 @@ "import fastavro\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "import pandas as pd\n", "import io\n", "from astropy.io import fits\n", "from astropy.wcs import WCS\n", "from astropy.coordinates import SkyCoord\n", + "from astropy.nddata import CCDData\n", + "from astropy.visualization import (MinMaxInterval, ZScaleInterval,\n", + " AsinhStretch, LinearStretch,\n", + " ImageNormalize)\n", "from astropy.wcs.utils import skycoord_to_pixel\n", "\n", "from lsst.rsp import RSPClient, get_service_url\n", - "import lsst.afw.display as afwDisplay\n", - "import lsst.afw.image as afwImage\n", "from lsst.utils.plotting import (get_multiband_plot_colors,\n", " get_multiband_plot_symbols)" ] @@ -136,7 +140,7 @@ "source": [ "### 1.2. Define parameters\n", "\n", - "Establish the connection to Herald by getting the `url` for the alerts retrieval service and instantiating the `RSPClient`." + "Establish the connection to the alert retrieval service by getting the `url` for the service and instantiating the `RSPClient`." ] }, { @@ -150,24 +154,6 @@ "client = RSPClient(\"\")" ] }, - { - "cell_type": "markdown", - "id": "7b7a30e7-8b45-4c0e-8994-fddce488724e", - "metadata": {}, - "source": [ - "Set the `afwDisplay` backend to `matplotlib`, to be used when displaying the image stamps." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8aecaa66-9ac5-4592-b8a1-c0f9a625c760", - "metadata": {}, - "outputs": [], - "source": [ - "afwDisplay.setDefaultBackend(\"matplotlib\")" - ] - }, { "cell_type": "markdown", "id": "15bd5483-126a-4652-b45c-10a98d702889", @@ -230,7 +216,7 @@ "source": [ "### 2.1. Retrieve the packets\n", "\n", - "An Avro Object Container File (OCF) is the default response format from Herald.\n", + "An Avro Object Container File (OCF) is the default response format from the alert retrieval service.\n", "Other formats (JSON, FITS) are possible, as demonstrated in the 100-level tutorial on the alert retrieval service.\n", "\n", "Pass the `url` to the `client` along with the `alert_id`.\n", @@ -865,7 +851,7 @@ } }, "source": [ - "Create `numpy` arrays of the previous detections." + "Create `pandas` dataframes of the previous detections." ] }, { @@ -875,17 +861,11 @@ "metadata": {}, "outputs": [], "source": [ - "band = []\n", - "mjd = []\n", - "flux = []\n", - "for pds in snia_record['prvDiaSources']:\n", - " band.append(pds['band'])\n", - " mjd.append(pds['midpointMjdTai'])\n", - " flux.append(pds['psfFlux'])\n", - "lc_band = np.asarray(band, dtype='str')\n", - "lc_mjd = np.asarray(mjd, dtype='float')\n", - "lc_flux = np.asarray(flux, dtype='float')\n", - "del band, mjd, flux" + "df = pd.DataFrame(snia_record['diaSource'], index=[0])\n", + "df_prv = pd.DataFrame(snia_record['prvDiaSources'])\n", + "df_lc = pd.concat([df, df_prv], ignore_index=True)\n", + "\n", + "del df, df_prv" ] }, { @@ -901,7 +881,7 @@ } }, "source": [ - "Create `numpy` arrays of the forced PSF photometry on the past images, which includes the image with the triggering detection." + "Create `pandas` dataframes of the forced PSF photometry on the past images, which includes the image with the triggering detection." ] }, { @@ -911,17 +891,11 @@ "metadata": {}, "outputs": [], "source": [ - "band = []\n", - "mjd = []\n", - "flux = []\n", - "for pds in snia_record['prvDiaForcedSources']:\n", - " band.append(pds['band'])\n", - " mjd.append(pds['midpointMjdTai'])\n", - " flux.append(pds['psfFlux'])\n", - "flc_band = np.asarray(band, dtype='str')\n", - "flc_mjd = np.asarray(mjd, dtype='float')\n", - "flc_flux = np.asarray(flux, dtype='float')\n", - "del band, mjd, flux" + "df = pd.DataFrame(snia_record['diaSource'], index=[0])\n", + "df_prv = pd.DataFrame(snia_record['prvDiaForcedSources'])\n", + "df_flc = pd.concat([df, df_prv], ignore_index=True)\n", + "\n", + "del df, df_prv" ] }, { @@ -948,15 +922,15 @@ " if alert_band == filt:\n", " ax[0].plot(alert_mjd-61000, alert_flux+offsets[f], filter_symbols[filt], ms=7,\n", " mew=2, alpha=1, color=filter_colors[filt])\n", - " fx = np.where(lc_band == filt)[0]\n", - " if len(fx) > 0:\n", - " ax[0].plot(lc_mjd[fx]-61000, lc_flux[fx]+offsets[f], filter_symbols[filt], ms=7,\n", - " mew=2, alpha=0.5, mec=filter_colors[filt], color='None')\n", - " fx = np.where(flc_band == filt)[0]\n", - " if len(fx) > 0:\n", - " ax[1].plot(flc_mjd[fx]-61000, flc_flux[fx]+offsets[f], filter_symbols[filt], ms=7,\n", - " mew=2, alpha=0.5, mec=filter_colors[filt], color='None',\n", - " label=filt + \" +\" + str(offsets[f]))\n", + " df_pick_band = df_lc.loc[df_lc['band'] == filt]\n", + " if len(df_pick_band) > 0:\n", + " ax[0].plot(df_pick_band['midpointMjdTai']-61000, df_pick_band['psfFlux']+offsets[f], filter_symbols[filt],\n", + " ms=5, mew=1, alpha=0.7, mec=filter_colors[filt], color='None')\n", + " df_pick_band = df_flc.loc[df_flc['band'] == filt]\n", + " if len(df_pick_band) > 0:\n", + " ax[1].plot(df_pick_band['midpointMjdTai']-61000, df_pick_band['psfFlux']+offsets[f], filter_symbols[filt],\n", + " ms=5, mew=1, alpha=0.7, mec=filter_colors[filt], color='None',\n", + " label=filt + \" +\" + str(offsets[f]))\n", "ax[0].set_xlabel('MJD-61000')\n", "ax[1].set_xlabel('MJD-61000')\n", "ax[0].set_ylabel('difference flux [nJy]')\n", @@ -1093,13 +1067,17 @@ "for s, (stamp, name) in enumerate(zip(stamps, stamp_names)):\n", " hdul = fits.HDUList.fromstring(stamp)\n", " data = hdul[0].data\n", - " image = afwImage.ImageF(data.astype(\"float32\"))\n", + " image = CCDData(data.astype(\"float32\"), unit='nJy')\n", + "# norm = ImageNormalize(image, interval=ZScaleInterval(),\n", + "# stretch=AsinhStretch())\n", + "# norm = ImageNormalize(image, interval=ZScaleInterval(),\n", + "# stretch=LinearStretch())\n", + " norm = ImageNormalize(image, interval=MinMaxInterval(),\n", + " stretch=LinearStretch())\n", " plt.sca(ax[s])\n", - " display = afwDisplay.Display(frame=fig)\n", - " # display.scale(\"asinh\", \"zscale\")\n", - " # display.scale(\"linear\", \"zscale\")\n", - " display.scale(\"linear\", \"minmax\")\n", - " display.image(image)\n", + " plt.imshow(image, origin='lower', norm=norm, cmap='gray')\n", + " plt.colorbar()\n", + " ax[s].set_title(name)\n", " plt.plot(pixels[0], pixels[0], 'o', ms=20, mew=1, color='None', mec='yellow')\n", " plt.plot([pixels[0], temp_pixels[0]], [pixels[1], temp_pixels[1]], color='cyan')\n", " plt.text(temp_pixels[0], temp_pixels[1], 'N', color='cyan', fontsize=12)\n", @@ -1140,11 +1118,12 @@ "for s, (stamp, name) in enumerate(zip(stamps, stamp_names)):\n", " hdul = fits.HDUList.fromstring(stamp)\n", " data = hdul[0].data\n", - " image = afwImage.ImageF(data.astype(\"float32\"))\n", + " image = CCDData(data.astype(\"float32\"), unit='nJy')\n", + " norm = ImageNormalize(image, interval=ZScaleInterval(),\n", + " stretch=LinearStretch())\n", " plt.sca(ax[s])\n", - " display = afwDisplay.Display(frame=fig)\n", - " display.scale(\"linear\", \"zscale\")\n", - " display.image(image)\n", + " plt.imshow(image, origin='lower', norm=norm, cmap='gray')\n", + " plt.colorbar()\n", " ax[s].set_title(name)\n", "plt.suptitle('Image stamps from the MBA alert')\n", "plt.tight_layout()\n", From 38e9435397a8d797bedecdb3961abb864aa25920 Mon Sep 17 00:00:00 2001 From: jeffcarlin Date: Thu, 28 May 2026 01:19:27 +0000 Subject: [PATCH 4/4] Address comments from Stelios and Eric --- .../101_Alert_archive/101_1_Alert_retrieval_service.ipynb | 7 +++++-- .../200_Data_products/201_Alerts/201_1_Alert_packets.ipynb | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service.ipynb b/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service.ipynb index a65c8152..a38c1bfc 100644 --- a/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service.ipynb +++ b/Prompt/100_How_to_use_RSP_tools/101_Alert_archive/101_1_Alert_retrieval_service.ipynb @@ -156,7 +156,9 @@ "id": "fc57297b-7457-46b4-9329-95f5993e50d5", "metadata": {}, "source": [ - "At the time this tutorial was prepared, the ALeRCE broker had identified the [object associated with this alert](https://lsst.alerce.online/object/170059286935240883?survey=lsst) as a potential Active Galactic Nucleus (AGN)." + "At the time this tutorial was prepared, the ALeRCE broker had identified the [object associated with this alert](https://lsst.alerce.online/object/170059286935240883?survey=lsst) as a potential Active Galactic Nucleus (AGN).\n", + "\n", + "Note that the alert retrieval service will also accept IAU-formatted IDs in the form of: LSST-AP-DS-170059317401616524, where the numerical portion is the `diaSourceId`." ] }, { @@ -191,6 +193,7 @@ "outputs": [], "source": [ "response = await client.get(url, params={\"ID\": alert_id})\n", + "response.raise_for_status()\n", "response?" ] }, @@ -851,7 +854,7 @@ "metadata": {}, "source": [ "**DIFFIM, SCIENCE, TEMPLATE**\\\n", - "Option to display the image stamp \"triplet\" of science, template, and difference image for the `dia_hdul`." + "Option to display the image stamp \"triplet\" of science, template, and difference image for the `hdul`." ] }, { diff --git a/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb b/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb index 8f00060b..1aad93c7 100644 --- a/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb +++ b/Prompt/200_Data_products/201_Alerts/201_1_Alert_packets.ipynb @@ -45,7 +45,7 @@ "\n", "**LSST data products:** Alert packets.\n", "\n", - "**Packages:** `lsst.rsp.RSPClient`, `lsst.rsp..get_service_url`, `fastavro`.\n", + "**Packages:** `lsst.rsp.RSPClient`, `lsst.rsp.get_service_url`, `fastavro`.\n", "\n", "**Credit:**\n", "Originally developed by Rubin Data Management team members.\n", @@ -1078,7 +1078,7 @@ " plt.imshow(image, origin='lower', norm=norm, cmap='gray')\n", " plt.colorbar()\n", " ax[s].set_title(name)\n", - " plt.plot(pixels[0], pixels[0], 'o', ms=20, mew=1, color='None', mec='yellow')\n", + " plt.plot(pixels[0], pixels[1], 'o', ms=20, mew=1, color='None', mec='yellow')\n", " plt.plot([pixels[0], temp_pixels[0]], [pixels[1], temp_pixels[1]], color='cyan')\n", " plt.text(temp_pixels[0], temp_pixels[1], 'N', color='cyan', fontsize=12)\n", " ax[s].set_title(name)\n",