Skip to content

Commit

Permalink
Merge pull request #10 from LCOGT/feature/line-analysis-backend
Browse files Browse the repository at this point in the history
Analysis Actions and Line Profile
  • Loading branch information
LTDakin authored May 6, 2024
2 parents 3216981 + 52459a9 commit 136d494
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
14 changes: 14 additions & 0 deletions datalab/datalab_session/analysis/line_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from skimage.measure import profile_line

from datalab.datalab_session.util import scale_points

# For creating an array of brightness along a user drawn line
def line_profile(input: dict, sci_hdu: object):
"""
Creates an array of luminosity values and the length of the line in arcseconds
"""
points = scale_points(input['width'], input['height'], sci_hdu.data, [(input["x1"], input["y1"]), (input["x2"], input["y2"])])
line_profile = profile_line(sci_hdu.data, points[0], points[1], mode="constant", cval=-1)
arcsec = len(line_profile) * sci_hdu.header["PIXSCALE"]

return {"line_profile": line_profile, "arcsec": arcsec}
44 changes: 44 additions & 0 deletions datalab/datalab_session/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import numpy as np

from django.conf import settings
from django.core.cache import cache

log = logging.getLogger()
log.setLevel(logging.INFO)
Expand Down Expand Up @@ -97,6 +98,29 @@ def get_archive_from_basename(basename: str) -> dict:

return results

def get_hdu(basename: str, extension: str = 'SCI') -> list[fits.HDUList]:
"""
Returns a list of Sci HDUs for the given basenames
Warning: this function returns an opened file that must be closed after use
"""

# use the basename to fetch and create a list of hdu objects
basename = basename.replace('-large', '').replace('-small', '')

if cache.get(f'{basename}-{extension}') is not None:
return cache.get(f'{basename}-{extension}')

archive_record = get_archive_from_basename(basename)

try:
fits_url = archive_record[0].get('url', 'No URL found')
except IndexError:
RuntimeWarning(f"No image found with specified basename: {basename}")

hdu = fits.open(fits_url, use_fsspec=True)
cache.set(f'{basename}-{extension}', hdu[extension])
return hdu[extension]

def create_fits(key: str, image_arr: np.ndarray) -> fits.HDUList:

header = fits.Header([('KEY', key)])
Expand All @@ -118,3 +142,23 @@ def stack_arrays(array_list: list):
stacked = np.stack(cropped_data_list, axis=2)

return stacked

def scale_points(small_img_width: int, small_img_height: int, img_array: list, points: list[tuple[int, int]]):
"""
Scale the coordinates from a smaller image to the full sized fits so we know the positions of the coords on the 2dnumpy array
Returns the list of tuple points with coords scaled for the numpy array
"""

large_height, large_width = np.shape(img_array)

# If the aspect ratios don't match we can't be certain where the point was
if small_img_width / small_img_height != large_width / large_height:
raise ValueError("Aspect ratios of the two images must match")

width_scale = large_width / small_img_width
height_scale = large_height / small_img_height

points_array = np.array(points)
scaled_points = np.int_(points_array * [width_scale, height_scale])

return scaled_points
21 changes: 21 additions & 0 deletions datalab/datalab_session/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from rest_framework.generics import RetrieveAPIView
from rest_framework.views import APIView
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response

from datalab.datalab_session.data_operations.utils import available_operations
from datalab.datalab_session.analysis.line_profile import line_profile
from datalab.datalab_session.util import get_hdu


class OperationOptionsApiView(RetrieveAPIView):
Expand All @@ -15,3 +18,21 @@ def get(self, request):
for operation_clazz in operations.values():
operation_details[operation_clazz.name()] = operation_clazz.wizard_description()
return Response(operation_details)

class AnalysisView(APIView):
"""
View to handle analysis actions and return the results
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

sci_hdu = get_hdu(input['basename'])

match action:
case 'line-profile':
output = line_profile(input, sci_hdu)
case _:
raise Exception(f'Analysis action {action} not found')

return Response(output)
3 changes: 2 additions & 1 deletion datalab/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import ocs_authentication.auth_profile.urls as authprofile_urls

from datalab.datalab_session.viewsets import DataSessionViewSet, DataOperationViewSet
from datalab.datalab_session.views import OperationOptionsApiView
from datalab.datalab_session.views import OperationOptionsApiView, AnalysisView

router = routers.SimpleRouter()
router.register(r'datasessions', DataSessionViewSet, 'datasessions')
Expand All @@ -35,6 +35,7 @@
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^api/', include(api_urlpatterns)),
path(r'api/analysis/<slug:action>/', AnalysisView.as_view(), name='analysis'),
path('api/available_operations/', OperationOptionsApiView.as_view(), name='available_operations'),
re_path(r'^authprofile/', include(authprofile_urls)),
]

0 comments on commit 136d494

Please sign in to comment.