Skip to content
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

source catalog and line profile use source for images, handle missing ra, dec, add clientAlertExceptions to analysis endpoint #42

Merged
merged 4 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions datalab/datalab_session/analysis/line_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def line_profile(input: dict):
y2 (int): The y coordinate of the ending point
}
"""
fits_path = get_fits(input['basename'])
fits_path = get_fits(input['basename'], input['source'])

sci_hdu = get_hdu(fits_path, 'SCI')

Expand Down Expand Up @@ -51,16 +51,16 @@ def line_profile(input: dict):
position_angle = coordinates.position_angle(start_sky_coord.ra, start_sky_coord.dec,
end_sky_coord.ra, end_sky_coord.dec).deg
except WcsError:
# no valid WCS solution
# Can't calculate these values without WCS
start_coords = None
end_coords = None
position_angle = None

# fallback attempt at using pixscale to calculate the arcsec distance
try:
# attempt using pixscale to calculate the angle
arcsec_angle = len(line_profile) * sci_hdu.header["PIXSCALE"]
except KeyError as e:
# no valid WCS solution, and no pixscale
except KeyError:
arcsec_angle = None

return {"line_profile": line_profile, "arcsec": arcsec_angle, "start_coords": start_coords, "end_coords": end_coords, "position_angle": position_angle}
line_profile_output = {"line_profile": line_profile, "arcsec": arcsec_angle, "start_coords": start_coords, "end_coords": end_coords, "position_angle": position_angle}
return line_profile_output
38 changes: 31 additions & 7 deletions datalab/datalab_session/analysis/source_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,28 @@
from datalab.datalab_session.file_utils import get_hdu, scale_points
from datalab.datalab_session.s3_utils import get_fits

# Source catalog Function Definition
# ARGS: input (dict)
# input = {
# basename (str): The name of the file to analyze
# height (int): The height of the image
# width (int): The width of the image
# source (str): The source of the file
# }
# RETURNS: output (dict)
# output = [{
# x (int): The x coordinate of the source
# y (int): The y coordinate of the source
# flux (int): The flux value of the source
# ra (float): The right ascension of the source
# dec (float): The declination of the source
# }]
#
def source_catalog(input: dict):
"""
Returns a dict representing the source catalog data with x,y coordinates and flux values
"""
fits_path = get_fits(input['basename'])
fits_path = get_fits(input['basename'], input['source'])

cat_hdu = get_hdu(fits_path, 'CAT')
sci_hdu = get_hdu(fits_path, 'SCI')
Expand All @@ -19,23 +36,30 @@ def source_catalog(input: dict):
x_points = cat_hdu.data["x"][:SOURCE_CATALOG_COUNT]
y_points = cat_hdu.data["y"][:SOURCE_CATALOG_COUNT]
flux = cat_hdu.data["flux"][:SOURCE_CATALOG_COUNT]
ra = cat_hdu.data["ra"][:SOURCE_CATALOG_COUNT]
dec = cat_hdu.data["dec"][:SOURCE_CATALOG_COUNT]

# ra, dec values may or may not be present in the CAT hdu
if "ra" in cat_hdu.data.names and "dec" in cat_hdu.data.names:
ra = cat_hdu.data["ra"][:SOURCE_CATALOG_COUNT]
dec = cat_hdu.data["dec"][:SOURCE_CATALOG_COUNT]
else:
# TODO: implement a fallback way to calculate ra, dec from x, y and WCS
ra = np.zeros(SOURCE_CATALOG_COUNT)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be cleaner to just not return ra/dec if they don't exist, and have the frontend check if they exist to show a message or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set them to null and don't include them in the return object, also added a check where they were used to fill out tool tip info in the frontend

dec = np.zeros(SOURCE_CATALOG_COUNT)

# scale the x_points and y_points from the fits pixel coords to the jpg coords
fits_height, fits_width = np.shape(sci_hdu.data)
x_points, y_points = scale_points(fits_height, fits_width, input['width'], input['height'], x_points=x_points, y_points=y_points)

# we will be giving a list of dicts representing each source back to the frontend
# create the list of source catalog objects
source_catalog_data = []
for i in range(SOURCE_CATALOG_COUNT):
source_catalog_data.append({
"x": x_points[i],
"y": y_points[i],
"flux": flux[i].astype(int),
# truncate the ra and dec to 4 decimal places for readability
"ra": '%.4f'%(ra[i]),
"dec": '%.4f'%(dec[i])
# Astronomical coordinates are formatted to 6 decimal places
"ra": '%.6f'%(ra[i]),
"dec": '%.6f'%(dec[i])
})

return source_catalog_data
4 changes: 3 additions & 1 deletion datalab/datalab_session/tests/test_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def test_line_profile(self, mock_get_fits):
'x1': 25,
'y1': 25,
'x2': 75,
'y2': 75
'y2': 75,
'source': 'archive'
})

assert_almost_equal(output.get('line_profile').tolist(), self.test_line_profile_data, decimal=3)
Expand All @@ -43,6 +44,7 @@ def test_source_catalog(self, mock_get_fits):
'basename': 'fits_1',
'height': 100,
'width': 100,
'source': 'archive'
})

self.assertEqual(output, self.test_source_catalog_data)
Original file line number Diff line number Diff line change
@@ -1,54 +1,54 @@
{
"test_source_catalog": [
{"x": 792, "y": 623, "flux": 3164455, "ra": "260.9333", "dec": "-33.0225"},
{"x": 919, "y": 120, "flux": 807813, "ra": "260.9667", "dec": "-32.9137"},
{"x": 996, "y": 627, "flux": 383099, "ra": "260.9861", "dec": "-33.0235"},
{"x": 997, "y": 641, "flux": 335359, "ra": "260.9862", "dec": "-33.0265"},
{"x": 587, "y": 803, "flux": 304833, "ra": "260.8802", "dec": "-33.0612"},
{"x": 1015, "y": 554, "flux": 291847, "ra": "260.9910", "dec": "-33.0076"},
{"x": 490, "y": 568, "flux": 226494, "ra": "260.8555", "dec": "-33.0101"},
{"x": 526, "y": 147, "flux": 209307, "ra": "260.8654", "dec": "-32.9191"},
{"x": 740, "y": 301, "flux": 177543, "ra": "260.9203", "dec": "-32.9526"},
{"x": 334, "y": 231, "flux": 168666, "ra": "260.8157", "dec": "-32.9370"},
{"x": 843, "y": 277, "flux": 132858, "ra": "260.9468", "dec": "-32.9476"},
{"x": 776, "y": 805, "flux": 115180, "ra": "260.9290", "dec": "-33.0618"},
{"x": 13, "y": 341, "flux": 101317, "ra": "260.7327", "dec": "-32.9604"},
{"x": 384, "y": 332, "flux": 93054, "ra": "260.8284", "dec": "-32.9590"},
{"x": 451, "y": 307, "flux": 82848, "ra": "260.8457", "dec": "-32.9536"},
{"x": 830, "y": 815, "flux": 76200, "ra": "260.9427", "dec": "-33.0641"},
{"x": 846, "y": 138, "flux": 70788, "ra": "260.9478", "dec": "-32.9176"},
{"x": 569, "y": 179, "flux": 69761, "ra": "260.8763", "dec": "-32.9261"},
{"x": 818, "y": 146, "flux": 69329, "ra": "260.9406", "dec": "-32.9191"},
{"x": 843, "y": 912, "flux": 63748, "ra": "260.9462", "dec": "-33.0851"},
{"x": 395, "y": 151, "flux": 60681, "ra": "260.8315", "dec": "-32.9198"},
{"x": 542, "y": 122, "flux": 60653, "ra": "260.8696", "dec": "-32.9136"},
{"x": 214, "y": 390, "flux": 60057, "ra": "260.7845", "dec": "-32.9712"},
{"x": 188, "y": 691, "flux": 59835, "ra": "260.7774", "dec": "-33.0363"},
{"x": 173, "y": 438, "flux": 59768, "ra": "260.7738", "dec": "-32.9816"},
{"x": 1022, "y": 188, "flux": 56811, "ra": "260.9931", "dec": "-32.9285"},
{"x": 431, "y": 936, "flux": 56575, "ra": "260.8396", "dec": "-33.0898"},
{"x": 333, "y": 112, "flux": 51136, "ra": "260.8157", "dec": "-32.9112"},
{"x": 211, "y": 958, "flux": 50722, "ra": "260.7828", "dec": "-33.0941"},
{"x": 664, "y": 535, "flux": 45352, "ra": "260.9004", "dec": "-33.0033"},
{"x": 989, "y": 975, "flux": 44414, "ra": "260.9838", "dec": "-33.0988"},
{"x": 1003, "y": 463, "flux": 38238, "ra": "260.9878", "dec": "-32.9879"},
{"x": 336, "y": 242, "flux": 37970, "ra": "260.8161", "dec": "-32.9393"},
{"x": 294, "y": 565, "flux": 37707, "ra": "260.8050", "dec": "-33.0093"},
{"x": 535, "y": 916, "flux": 37575, "ra": "260.8666", "dec": "-33.0854"},
{"x": 66, "y": 415, "flux": 37365, "ra": "260.7463", "dec": "-32.9765"},
{"x": 533, "y": 91, "flux": 36539, "ra": "260.8673", "dec": "-32.9069"},
{"x": 879, "y": 505, "flux": 35138, "ra": "260.9559", "dec": "-32.9970"},
{"x": 293, "y": 638, "flux": 34703, "ra": "260.8045", "dec": "-33.0250"},
{"x": 444, "y": 635, "flux": 33406, "ra": "260.8434", "dec": "-33.0245"},
{"x": 400, "y": 82, "flux": 33366, "ra": "260.8330", "dec": "-32.9048"},
{"x": 465, "y": 59, "flux": 32920, "ra": "260.8497", "dec": "-32.8998"},
{"x": 874, "y": 50, "flux": 32280, "ra": "260.9553", "dec": "-32.8984"},
{"x": 1007, "y": 416, "flux": 29422, "ra": "260.9892", "dec": "-32.9779"},
{"x": 281, "y": 294, "flux": 28626, "ra": "260.8019", "dec": "-32.9506"},
{"x": 682, "y": 39, "flux": 28508, "ra": "260.9057", "dec": "-32.8959"},
{"x": 972, "y": 426, "flux": 27457, "ra": "260.9801", "dec": "-32.9799"},
{"x": 480, "y": 557, "flux": 26744, "ra": "260.8529", "dec": "-33.0077"},
{"x": 812, "y": 291, "flux": 25618, "ra": "260.9389", "dec": "-32.9506"},
{"x": 443, "y": 206, "flux": 25483, "ra": "260.8438", "dec": "-32.9317"}
{"x": 792, "y": 623, "flux": 3164455, "ra": "260.933350", "dec": "-33.022468"},
{"x": 919, "y": 120, "flux": 807813, "ra": "260.966724", "dec": "-32.913659"},
{"x": 996, "y": 627, "flux": 383099, "ra": "260.986084", "dec": "-33.023544"},
{"x": 997, "y": 641, "flux": 335359, "ra": "260.986153", "dec": "-33.026504"},
{"x": 587, "y": 803, "flux": 304833, "ra": "260.880190", "dec": "-33.061203"},
{"x": 1015, "y": 554, "flux": 291847, "ra": "260.990955", "dec": "-33.007606"},
{"x": 490, "y": 568, "flux": 226494, "ra": "260.855531", "dec": "-33.010065"},
{"x": 526, "y": 147, "flux": 209307, "ra": "260.865447", "dec": "-32.919082"},
{"x": 740, "y": 301, "flux": 177543, "ra": "260.920254", "dec": "-32.952604"},
{"x": 334, "y": 231, "flux": 168666, "ra": "260.815714", "dec": "-32.937012"},
{"x": 843, "y": 277, "flux": 132858, "ra": "260.946803", "dec": "-32.947639"},
{"x": 776, "y": 805, "flux": 115180, "ra": "260.929046", "dec": "-33.061751"},
{"x": 13, "y": 341, "flux": 101317, "ra": "260.732683", "dec": "-32.960356"},
{"x": 384, "y": 332, "flux": 93054, "ra": "260.828434", "dec": "-32.958980"},
{"x": 451, "y": 307, "flux": 82848, "ra": "260.845680", "dec": "-32.953588"},
{"x": 830, "y": 815, "flux": 76200, "ra": "260.942738", "dec": "-33.064078"},
{"x": 846, "y": 138, "flux": 70788, "ra": "260.947787", "dec": "-32.917576"},
{"x": 569, "y": 179, "flux": 69761, "ra": "260.876290", "dec": "-32.926068"},
{"x": 818, "y": 146, "flux": 69329, "ra": "260.940558", "dec": "-32.919116"},
{"x": 843, "y": 912, "flux": 63748, "ra": "260.946216", "dec": "-33.085093"},
{"x": 395, "y": 151, "flux": 60681, "ra": "260.831455", "dec": "-32.919758"},
{"x": 542, "y": 122, "flux": 60653, "ra": "260.869564", "dec": "-32.913619"},
{"x": 214, "y": 390, "flux": 60057, "ra": "260.784459", "dec": "-32.971195"},
{"x": 188, "y": 691, "flux": 59835, "ra": "260.777363", "dec": "-33.036278"},
{"x": 173, "y": 438, "flux": 59768, "ra": "260.773825", "dec": "-32.981611"},
{"x": 1022, "y": 188, "flux": 56811, "ra": "260.993067", "dec": "-32.928477"},
{"x": 431, "y": 936, "flux": 56575, "ra": "260.839617", "dec": "-33.089795"},
{"x": 333, "y": 112, "flux": 51136, "ra": "260.815677", "dec": "-32.911207"},
{"x": 211, "y": 958, "flux": 50722, "ra": "260.782797", "dec": "-33.094140"},
{"x": 664, "y": 535, "flux": 45352, "ra": "260.900375", "dec": "-33.003295"},
{"x": 989, "y": 975, "flux": 44414, "ra": "260.983777", "dec": "-33.098763"},
{"x": 1003, "y": 463, "flux": 38238, "ra": "260.987847", "dec": "-32.987939"},
{"x": 336, "y": 242, "flux": 37970, "ra": "260.816099", "dec": "-32.939259"},
{"x": 294, "y": 565, "flux": 37707, "ra": "260.804958", "dec": "-33.009319"},
{"x": 535, "y": 916, "flux": 37575, "ra": "260.866625", "dec": "-33.085422"},
{"x": 66, "y": 415, "flux": 37365, "ra": "260.746322", "dec": "-32.976492"},
{"x": 533, "y": 91, "flux": 36539, "ra": "260.867257", "dec": "-32.906923"},
{"x": 879, "y": 505, "flux": 35138, "ra": "260.955856", "dec": "-32.996953"},
{"x": 293, "y": 638, "flux": 34703, "ra": "260.804463", "dec": "-33.024956"},
{"x": 444, "y": 635, "flux": 33406, "ra": "260.843397", "dec": "-33.024536"},
{"x": 400, "y": 82, "flux": 33366, "ra": "260.832988", "dec": "-32.904823"},
{"x": 465, "y": 59, "flux": 32920, "ra": "260.849739", "dec": "-32.899831"},
{"x": 874, "y": 50, "flux": 32280, "ra": "260.955293", "dec": "-32.898351"},
{"x": 1007, "y": 416, "flux": 29422, "ra": "260.989158", "dec": "-32.977875"},
{"x": 281, "y": 294, "flux": 28626, "ra": "260.801870", "dec": "-32.950643"},
{"x": 682, "y": 39, "flux": 28508, "ra": "260.905706", "dec": "-32.895904"},
{"x": 972, "y": 426, "flux": 27457, "ra": "260.980081", "dec": "-32.979940"},
{"x": 480, "y": 557, "flux": 26744, "ra": "260.852921", "dec": "-33.007667"},
{"x": 812, "y": 291, "flux": 25618, "ra": "260.938918", "dec": "-32.950600"},
{"x": 443, "y": 206, "flux": 25483, "ra": "260.843795", "dec": "-32.931662"}
]
}
47 changes: 32 additions & 15 deletions datalab/datalab_session/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging

from rest_framework.generics import RetrieveAPIView
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
Expand All @@ -7,6 +9,7 @@
from datalab.datalab_session.analysis.source_catalog import source_catalog
from datalab.datalab_session.analysis.get_tif import get_tif
from datalab.datalab_session.analysis.raw_data import raw_data
from datalab.datalab_session.exceptions import ClientAlertException


class OperationOptionsApiView(RetrieveAPIView):
Expand All @@ -26,18 +29,32 @@ class AnalysisView(RetrieveAPIView):
To add a new analysis action, add a case to the switch statement and create a new file in the analysis directory
"""
def post(self, request, action):
input = request.data

match action:
case 'line-profile':
output = line_profile(input)
case 'source-catalog':
output = source_catalog(input)
case 'get-tif':
output = get_tif(input)
case 'raw-data':
output = raw_data(input)
case _:
raise Exception(f'Analysis action {action} not found')

return Response(output)
log = logging.getLogger()
log.setLevel(logging.INFO)

try:
# TODO replace switch case with an AnalysisAction class
# AnalysisAction Class Definition
# class AnalysisAction:
# def __init__(self, action):
# def run(self, input):
# def name(self):
input = request.data

match action:
case 'line-profile':
output = line_profile(input)
case 'source-catalog':
output = source_catalog(input)
case 'get-tif':
output = get_tif(input)
case 'raw-data':
output = raw_data(input)
case _:
raise Exception(f'Analysis action {action} not found')

return Response(output)

except ClientAlertException as error:
log.error(f"Error running analysis action {action}: {error}")
return Response({"error": f"Image doesn't support {action}"}, status=400)
Loading