Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions public/drawImageWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ async function processScalePoints(scalePoints) {
const srcData = imageData.data
const scale = 255 / (high16Bit - low16Bit)

// Loop through each pixel, normalize according to the Zscale (low16bit, high16bit) and apply gamma correction
for (let i = 0; i < len; i++) {
const clippedValue = Math.max(low16Bit, Math.min(high16Bit, srcData[i]))
const normalizedValue = Math.floor((clippedValue - low16Bit) * scale)
Expand Down
4 changes: 2 additions & 2 deletions src/components/Analysis/FitsHeaderTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { useAnalysisStore } from '@/stores/analysis'

const analysisStore = useAnalysisStore()

const search = ref('')

const search = ref('') // v-data-table search model
const headerDataKeyValueList = Object.entries(analysisStore.headerData)

const tableHeaders = [
{ title: 'Key', key:'0' },
{ title: 'Value', sortable: false, key:'1' },
]

// Loopable chip dict for v-chips
const headerChips = computed(() => [
{ icon: 'mdi-earth', text: siteIDToName(analysisStore.headerData.SITEID) },
{ icon: 'mdi-telescope', text: analysisStore.headerData.TELID },
Expand Down
17 changes: 11 additions & 6 deletions src/components/Analysis/ImageViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@ const showVariableStarDialog = ref(false)
const variableTargetCoords = ref({ ra: null, dec: null })

onMounted(() => {
// Initialize the map and its event listeners before adding the image overlay
createMap()
addMapHandlers()
})

// When the catalog is updated we want to recreate the catalog layer
watch(() => props.catalog, () => createCatalogLayer())

// update url property of the ImageOverlay Layer or create it
watch(() => analysisStore.imageUrl, (newImageUrl) => {
imageOverlay ? imageOverlay.setUrl(newImageUrl) : initImageOverlay(newImageUrl)
})

// Loads image overlay and sets bounds
// Creates image overlay and sets bounds
async function initImageOverlay(imgSrc) {
const img = await loadImage(imgSrc)
imageDimensions.value = { width: img.width, height: img.height }
Expand All @@ -74,7 +77,7 @@ async function initImageOverlay(imgSrc) {

/**
* Fills map space with image, set max/min zoom
* Next tick is used here otherwise the methods will not work due to bugs in leaflets code.
* Next tick is used here otherwise the bounds will update before the ImageOverlay is added to the map
*/
nextTick(() => {
imageMap.invalidateSize()
Expand All @@ -85,15 +88,15 @@ async function initImageOverlay(imgSrc) {
}

function createMap(){
// Create leaflet map (here referred to as image)
// Create leaflet map (here referred to as imageMap)
imageMap = L.map(leafletDiv.value, {
maxZoom: 5,
minZoom: -3,
zoomSnap: 0,
zoomSnap: 0, // disable snap for smooth zoom
zoomDelta: 0.5,
crs: L.CRS.Simple,
attributionControl: false,
maxBoundsViscosity: 1.0,
maxBoundsViscosity: 1.0, // Prevents panning outside of image
})

// Create custom control to reset view after zooming in
Expand Down Expand Up @@ -132,8 +135,8 @@ function createMap(){
}

function addMapHandlers() {
// Remove last drawn line when starting new one
imageMap.on('pm:drawstart', ({ workingLayer }) => {
// Remove last drawn line when starting new one
if (lineLayer && imageMap.hasLayer(lineLayer)) {
imageMap.removeLayer(lineLayer)
}
Expand Down Expand Up @@ -165,6 +168,8 @@ function addMapHandlers() {
const fitsWidth = wcs.fits_dimensions[0]
const fitsHeight = wcs.fits_dimensions[1]

// TODO: up to here might be able to be moved outside of the mousemove event

const imageX = e.latlng.lng
const imageY = e.latlng.lat

Expand Down
19 changes: 10 additions & 9 deletions src/components/Analysis/LightCurvePlot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ let lightCurveChart = null
const CHART_PADDING = 0.5
const DECIMAL_PLACES = 4

// Chart data for brightness over linear time
const chartData = computed(() => {
const magTimeSeries = analysisStore.magTimeSeries

const dates = magTimeSeries.map(({ julian_date }) => julian_date)
const magnitudes = magTimeSeries.map(({ mag }) => mag.toFixed(DECIMAL_PLACES))
// Error bars as [lowerBound, upperBound]
const errors = magTimeSeries.map(({ mag, magerr }) => {
const lowerBound = (mag - magerr).toFixed(DECIMAL_PLACES)
const upperBound = (mag + magerr).toFixed(DECIMAL_PLACES)
return [lowerBound, upperBound]
})

// Formatted dict for the chart to use
return {
dates: dates,
magnitudes: magnitudes,
Expand All @@ -35,18 +38,19 @@ watch(() => analysisStore.variableStarData, () => {
}, { deep: true})

function updateChart() {
// Updates the chart when user runs flux analysis again
// Set all the new data
const { dates, magnitudes, errors, chartMin, chartMax } = chartData.value
lightCurveChart.data.labels = dates
lightCurveChart.data.datasets[0].data = magnitudes
lightCurveChart.data.datasets[1].data = errors
lightCurveChart.options.scales.y.min = chartMin
lightCurveChart.options.scales.y.max = chartMax
// Call Chart.js update method
lightCurveChart.update()
}

function createChart() {
// chartJs can't use css vars as strings, so we need to get the actual value
// chartJs can't use css vars as strings, so we need to get the values
var style = getComputedStyle(document.body)
const text = style.getPropertyValue('--text')
const primary = style.getPropertyValue('--primary-interactive')
Expand All @@ -61,27 +65,24 @@ function createChart() {
data: {
labels: dates,
datasets: [
{
{ // Main magnitude dataset is a line chart
label: 'Magnitude',
data: magnitudes,
order: 0,
// Line styling
borderColor: primary,
borderWidth: 2,
borderJoinStyle: 'round',
backgroundColor: primary,
cubicInterpolationMode: 'monotone',
tension: 0.4,
// Point hover styling
pointHoverBorderColor: secondary,
pointHoverBackgroundColor: secondary,
},
{
{ // Error bar dataset is a bar chart overlaid
label: 'Mag Error',
data: errors,
order: 1,
type: 'bar',
// Error bar styling
borderColor: info,
backgroundColor: info,
barPercentage: 0.1,
Expand All @@ -92,7 +93,7 @@ function createChart() {
},
options: {
scales: {
x: {
x: { // Formating the x time axis
type: 'timeseries',
title: { display: true, text: 'Date', color: text },
border: { color: text, width: 2 },
Expand All @@ -119,7 +120,7 @@ function createChart() {
legend: { display: false },
tooltip: { mode: 'index', intersect: false },
},
hover: {
hover: { // A more permissive hover that doesn't require intersecting a point
mode: 'index',
intersect: false,
}
Expand Down
11 changes: 6 additions & 5 deletions src/components/Analysis/LinePlot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function createChart (){
data: {
labels: generateLabels(),
datasets: [
{
{ // Flux value along the drawn line as a line plot
label: 'Flux',
data: props.yAxisData,
// Line styling
Expand All @@ -49,7 +49,7 @@ function createChart (){
},
options: {
scales: {
x: {
x: { // Autoskip labels if there are too many to display
title: { display: true, text: distanceLabel(), color: text },
border: { color: text, width: 2 },
ticks: { color: text, autoSkip: true, autoSkipPadding: 10 , maxRotation: 0 },
Expand All @@ -66,7 +66,7 @@ function createChart (){
legend: { display: false },
tooltip: { mode: 'index', intersect: false },
},
hover: {
hover: { // Permissive hover, shows tooltips when cursor is near a point
mode: 'index',
intersect: false,
}
Expand All @@ -75,13 +75,14 @@ function createChart (){
}

function updateChart(){
// Set the changed data
lineProfileChart.data.labels = generateLabels()
lineProfileChart.data.datasets[0].data = props.yAxisData
lineProfileChart.options.scales.x.title.text = distanceLabel()
// Call Chart.js update method
lineProfileChart.update()
}

// Creates the labels for the x-axis
// Uses length of the line to generate step size in arcseconds or pixels as x-axis labels
function generateLabels() {
const length = props.xAxisLength
const data = props.yAxisData
Expand Down
9 changes: 6 additions & 3 deletions src/components/Analysis/PeriodPlot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const periodCanvas = ref(null)
let periodChart = null
const DECIMAL_PLACES = 4

// Determines color of the false alarm probability chip
const probabilityChipColor = computed(() => {
const ONE_SIGMA = 0.32
const TWO_SIGMA = 0.045
Expand All @@ -18,6 +19,7 @@ const probabilityChipColor = computed(() => {
return 'var(--red)'
})

// Periodogram data formatted for chartJs
const chartData = computed(() => {
const periodogram = analysisStore.variableStarData.magPeriodogram

Expand All @@ -37,10 +39,11 @@ watch(() => analysisStore.variableStarData, () => {
}, { deep: true})

function updateChart() {
// Updates the chart when user runs flux analysis again
// Updates the chart with new data
const { period1, period2 } = chartData.value
periodChart.data.datasets[0].data = period1
periodChart.data.datasets[1].data = period2
// Call Chart.js update method
periodChart.update()
}

Expand All @@ -58,14 +61,14 @@ function createChart() {
periodChart = new Chart(periodCanvas.value, {
data: {
datasets: [
{
{ // First Period
type: 'scatter',
label: 'Period 1',
data: period1,
backgroundColor: primary,
pointHoverBackgroundColor: info,
},
{
{ // Second Period (Phase + 1)
type: 'scatter',
label: 'Period 2',
data: period2,
Expand Down
11 changes: 7 additions & 4 deletions src/components/Analysis/VariableStarDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ const configStore = useConfigurationStore()
const analysisStore = useAnalysisStore()
const alertsStore = useAlertsStore()

// Date range to query images from the archive, default to last 7 days
const endDate = ref(new Date(analysisStore.headerData.DATE))
const startDate = ref(new Date(endDate.value))
startDate.value.setDate(endDate.value.getDate() - 7)
const matchingImages = ref({ count: 0, results: [] })

const ISOStartDate = computed(() => startDate.value.toISOString())
const ISOEndDate = computed(() => endDate.value.toISOString())

const matchingImages = ref({ count: 0, results: [] })

// When date range changes, queries the archive and updates tooltip with how many images are available
watch([startDate, endDate], () => {
const { datalabArchiveApiUrl } = configStore
const { imageFilter, imageProposalId } = analysisStore
Expand All @@ -49,16 +51,17 @@ watch([startDate, endDate], () => {
})
}, { immediate: true })

// Run when user clicks "Analyze" kicks off the variable star analysis
function dispatchVariableAnalysis() {
emit ('analysisAction', 'variable-star', {
images: matchingImages.value.results.map((image) => {
images: matchingImages.value.results.map((image) => { // a list of images
return {
id: image.id,
basename: image.basename,
observation_date: image.observation_date,
}
}),
target_coords: props.coords,
target_coords: props.coords, // the target coordinates
})
analysisStore.variableStarData.loading = true
emit('closeDialog')
Expand Down
26 changes: 16 additions & 10 deletions src/components/DataSession/DataSession.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,32 @@ const POLL_WAIT_TIME = 5000

var operationMap = {}

// When a user clicks on an operation, we filter to only show the outputs of that operation
const filteredImages = computed(() => {
// If no operation is selected, return all images, otherwise filter by selected operation
if (selectedOperation.value === -1) {
return images.value
} else {
return images.value.filter(image => image.operation === selectedOperation.value)
}
})

// Runs when a user clicks on an operation to select/deselect it
function selectOperation(operationId) {
if (operationId == selectedOperation.value) {
selectedOperation.value = -1
}
else {
selectedOperation.value = operationId
}
}


// Image Equality Check
function imagesContainsFile(file) {
return images.value.some(image => image.basename == file.basename && image.source == file.source && image.operation == file.operation)
}

// Add completed operation images to image list and attach operation metadata to identify their source
function addCompletedOperation(operation) {
if ('output' in operation && 'output_files' in operation.output) {
operation.output.output_files.forEach(outputFile => {
Expand All @@ -61,15 +74,6 @@ function addCompletedOperation(operation) {
}
}

function selectOperation(operationId) {
if (operationId == selectedOperation.value) {
selectedOperation.value = -1
}
else {
selectedOperation.value = operationId
}
}

async function addOperation(operationDefinition) {
const url = dataSessionsUrl + props.data.id + '/operations/'

Expand Down Expand Up @@ -103,6 +107,7 @@ function operationDeleted(operationIDs){
})
}

// Main lifecycle function for managing operation polling and updates
async function pollOperationCompletion(operation) {
// Success Callback for checking operation status
const updateOperationStatus = (response) => {
Expand Down Expand Up @@ -143,6 +148,7 @@ async function pollOperationCompletion(operation) {
await fetchApiCall({ url: url, method: 'GET', successCallback: updateOperationStatus, failCallback: handleError })
}

// Kicks off the lifecycle function above for any operations that are not completed
function startOperationPolling() {
operations.value.forEach(operation => {
if (operation.status != 'COMPLETED' && operation.status != 'FAILED') {
Expand Down
2 changes: 2 additions & 0 deletions src/components/DataSession/MultiImageInputSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ onMounted(() => {
imageDetails.value = reloadImages(props.images)
})

// Image dragged into the selected images area
function insert(inputKey, event) {
if (inputKey !== 'all' && ! props.selectedImages[inputKey].includes(event.data)) {
emit('insertSelectedImage', inputKey, event.data)
}
}

// Image removed from the selected images area
function remove(inputKey, value) {
if (inputKey !== 'all') {
emit('removeSelectedImage', inputKey, value)
Expand Down
Loading