Skip to content

Commit

Permalink
Merge pull request #27 from gemini-hlsw/SCHED-603
Browse files Browse the repository at this point in the history
SCHED 603: Add twilights to schedule plot
  • Loading branch information
stroncod authored Feb 12, 2024
2 parents db7129e + 4d58065 commit 87cfdd0
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 26 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"highcharts": "^11.0.0",
"highcharts-react-official": "^3.2.0",
"lucuma-ui-css": "^0.63.1",
"moment-timezone": "^0.5.45",
"primeicons": "^6.0.1",
"primereact": "^10.2.1",
"react": "^18.2.0",
Expand Down Expand Up @@ -55,4 +56,4 @@
"vite": "^4.0.2"
},
"description": "GPP Schedule app"
}
}
2 changes: 2 additions & 0 deletions src/components/ControlPanel/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export const scheduleQuery = graphql(`
nightIndex
timeEntriesBySite{
site,
mornTwilight,
eveTwilight,
timeEntries{
startTimeSlots,
event,
Expand Down
4 changes: 3 additions & 1 deletion src/components/Results/EntryBySite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ export default function EntryBySite({
<div className="site-entry">
<h4 className="title">Timeline</h4>
<div className="timeline">{timeLine}</div>
<TimeEntry timeEntry={selectedEntry} />
<TimeEntry timeEntry={selectedEntry}
eveTwilight={entryBySite.eveTwilight}
mornTwilight={entryBySite.mornTwilight}/>
</div>
);
}
9 changes: 7 additions & 2 deletions src/components/Results/TimeEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import moment from 'moment-timezone';
import { TimeEntryType, Visit } from "../../types";
import NightPlanSummary from "./NightPlanSummary";
import AltAzPlot from "../SchedulerPlot/SchedulerPlot";
Expand All @@ -9,8 +10,12 @@ import { Tag } from 'primereact/tag';
import { ProgressBar } from 'primereact/progressbar';


export default function TimeEntry({ timeEntry }: { timeEntry: TimeEntryType }) {
export default function TimeEntry({timeEntry, mornTwilight, eveTwilight}: {timeEntry: TimeEntryType,
mornTwilight: string,
eveTwilight: string}) {
function parseToVisitForPlot(visits: Visit[]) {
console.log(visits[0].startTime)
console.log( moment.utc(visits[0].startTime).tz('Pacific/Honolulu').toDate())
return visits.map((visit: Visit) => ({
startDate: new Date(visit.startTime),
endDate: new Date(visit.endTime),
Expand Down Expand Up @@ -87,7 +92,7 @@ export default function TimeEntry({ timeEntry }: { timeEntry: TimeEntryType }) {
nightState={timeEntry.plan.nightStats}
nightTitle={timeEntry.plan.startTime.substring(0, timeEntry.plan.startTime.indexOf('T'))} />}
>
<AltAzPlot data={parseToVisitForPlot(timeEntry.plan.visits)} />
<AltAzPlot data={parseToVisitForPlot(timeEntry.plan.visits)} eveTwilight={eveTwilight} mornTwilight={mornTwilight} />
<DataTable value={timeEntry.plan.visits} tableStyle={{ minWidth: '50rem' }}>
<Column field="obsId" header="Observation ID"> </Column>
<Column header="Observation Class" body={obsClassBodyTemplate}></Column>
Expand Down
60 changes: 42 additions & 18 deletions src/components/SchedulerPlot/SchedulerPlot.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useContext, useEffect, useRef } from 'react';
import React, { useContext, useEffect, useRef, useState } from 'react';
import moment from 'moment-timezone';
import Highcharts, { SeriesArearangeOptions } from 'highcharts';
import HighchartsReact, { HighchartsReactRefObject } from 'highcharts-react-official';
import HighchartMore from 'highcharts/highcharts-more';
Expand All @@ -17,10 +18,12 @@ interface Visit {

interface AltAzPlotProps {
data: Visit[];
eveTwilight: string,
mornTwilight: string
}


const AltAzPlot: React.FC<AltAzPlotProps> = ({ data }) => {
const AltAzPlot: React.FC<AltAzPlotProps> = ({ data, eveTwilight, mornTwilight}) => {

// Get theme context to modify chart values
const { theme } = useContext(ThemeContext);
Expand Down Expand Up @@ -51,15 +54,15 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data }) => {
return map;
};
const colorMap = createMap(instruments, colors);
const eveTwiDate = new Date (eveTwilight)
const mornTwiDate = new Date (mornTwilight)



const seriesData: Array<SeriesArearangeOptions> = data.map((d, index) => {
const yMinArray = d.yPoints.map((y) => 0);
const seriesData: Array<SeriesArearangeOptions> = data.map((d: any, index: number) => {
const yMinArray = d.yPoints.map((y: number) => 0);
return {
name: d.instrument,
type: "arearange",
data: d.yPoints.map((y, i) => {
data: d.yPoints.map((y: any, i: number) => {
return {
x: d.startDate.getTime() + i * 60 * 1000,
low: yMinArray[i],
Expand All @@ -73,7 +76,11 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data }) => {
marker: {
enabled: false,
},

events: {
legendItemClick: function() {
return false; // Prevents the default action, which is toggling visibility
}
},
showInLegend: true, // Hide this series in the legend
};
});
Expand All @@ -90,7 +97,6 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data }) => {
}
}


useEffect(() => {
if (chartRef.current) {
const chart = chartRef.current.chart;
Expand Down Expand Up @@ -126,9 +132,26 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data }) => {
}, seriesData);

const options: Highcharts.Options = {
time: {
timezone: 'Pacific/Honolulu'
},
chart: {
type: "arearange",
},

tooltip: {
// Use the shared tooltip to show information for the entire area
shared: true,
formatter: function () {
if (this.points) {
var points = this.points;
// Assuming the first point is representative for the area
var point = this.series.name;
return point;
}
return false; // No tooltip for individual points
}
},
title: {
text: undefined,
},
Expand All @@ -142,18 +165,18 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data }) => {
color: textColor, // Change the color of y-axis tick labels
},
},
min: eveTwiDate.getTime(),
max: mornTwiDate.getTime(),
tickPositioner: function () {
const minTimestamp = Math.min(...data.map((d) => d.startDate.getTime()));
const maxTimestamp = Math.max(...data.map((d) => d.endDate.getTime()));
const oneHour = 1000 * 60 * 60;
var positions = []
var interval = 1 * 60 * 60 * 1000

const tickPositions = [];
for (let timestamp = minTimestamp; timestamp <= maxTimestamp; timestamp += oneHour) {
tickPositions.push(timestamp);
}
for (var i = eveTwiDate.getTime(); i <= mornTwiDate.getTime(); i+=interval){
positions.push(i);
}
return positions;
}

return tickPositions;
},
},
yAxis: {
title: {
Expand All @@ -180,6 +203,7 @@ const AltAzPlot: React.FC<AltAzPlotProps> = ({ data }) => {

return (
<div className='scheduler-plot'>

<HighchartsReact highcharts={Highcharts} options={options} ref={chartRef} />
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/gql/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
* Therefore it is highly recommended to use the babel-plugin for production.
*/
const documents = {
"\n query schedule($startTime: String!,\n $endTime: String!,\n $sites: Sites!,\n $mode: SchedulerModes!,\n $numNightsToSchedule: Int!,\n $thesisFactor: Float,\n $power: Int,\n $metPower: Float,\n $visPower: Float,\n $whaPower: Float ) {\n schedule(\n newScheduleInput: {\n startTime: $startTime, \n numNightsToSchedule: $numNightsToSchedule , \n sites: $sites, \n mode: $mode, \n endTime: $endTime,\n semesterVisibility:false,\n thesisFactor: $thesisFactor,\n power: $power,\n visPower: $visPower,\n metPower: $metPower,\n whaPower: $whaPower}\n ) {\n nightPlans{\n nightTimeline{\n nightIndex\n timeEntriesBySite{\n site,\n timeEntries{\n startTimeSlots,\n event,\n plan{\n startTime,\n visits{\n obsId,\n endTime,\n altitude,\n atomEndIdx,\n atomStartIdx,\n startTime,\n instrument,\n score,\n obsClass,\n completion,\n peakScore,\n },\n nightStats{\n timeloss,\n planScore,\n timeloss,\n nToos,\n completionFraction,\n }\n }\n }\n }\n }\n },\n plansSummary\n }\n }\n": types.ScheduleDocument,
"\n query schedule($startTime: String!,\n $endTime: String!,\n $sites: Sites!,\n $mode: SchedulerModes!,\n $numNightsToSchedule: Int!,\n $thesisFactor: Float,\n $power: Int,\n $metPower: Float,\n $visPower: Float,\n $whaPower: Float ) {\n schedule(\n newScheduleInput: {\n startTime: $startTime, \n numNightsToSchedule: $numNightsToSchedule , \n sites: $sites, \n mode: $mode, \n endTime: $endTime,\n semesterVisibility:false,\n thesisFactor: $thesisFactor,\n power: $power,\n visPower: $visPower,\n metPower: $metPower,\n whaPower: $whaPower}\n ) {\n nightPlans{\n nightTimeline{\n nightIndex\n timeEntriesBySite{\n site,\n mornTwilight,\n eveTwilight,\n timeEntries{\n startTimeSlots,\n event,\n plan{\n startTime,\n visits{\n obsId,\n endTime,\n altitude,\n atomEndIdx,\n atomStartIdx,\n startTime,\n instrument,\n score,\n obsClass,\n completion,\n peakScore,\n },\n nightStats{\n timeloss,\n planScore,\n timeloss,\n nToos,\n completionFraction,\n }\n }\n }\n }\n }\n },\n plansSummary\n }\n }\n": types.ScheduleDocument,
};

/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query schedule($startTime: String!,\n $endTime: String!,\n $sites: Sites!,\n $mode: SchedulerModes!,\n $numNightsToSchedule: Int!,\n $thesisFactor: Float,\n $power: Int,\n $metPower: Float,\n $visPower: Float,\n $whaPower: Float ) {\n schedule(\n newScheduleInput: {\n startTime: $startTime, \n numNightsToSchedule: $numNightsToSchedule , \n sites: $sites, \n mode: $mode, \n endTime: $endTime,\n semesterVisibility:false,\n thesisFactor: $thesisFactor,\n power: $power,\n visPower: $visPower,\n metPower: $metPower,\n whaPower: $whaPower}\n ) {\n nightPlans{\n nightTimeline{\n nightIndex\n timeEntriesBySite{\n site,\n timeEntries{\n startTimeSlots,\n event,\n plan{\n startTime,\n visits{\n obsId,\n endTime,\n altitude,\n atomEndIdx,\n atomStartIdx,\n startTime,\n instrument,\n score,\n obsClass,\n completion,\n peakScore,\n },\n nightStats{\n timeloss,\n planScore,\n timeloss,\n nToos,\n completionFraction,\n }\n }\n }\n }\n }\n },\n plansSummary\n }\n }\n"): (typeof documents)["\n query schedule($startTime: String!,\n $endTime: String!,\n $sites: Sites!,\n $mode: SchedulerModes!,\n $numNightsToSchedule: Int!,\n $thesisFactor: Float,\n $power: Int,\n $metPower: Float,\n $visPower: Float,\n $whaPower: Float ) {\n schedule(\n newScheduleInput: {\n startTime: $startTime, \n numNightsToSchedule: $numNightsToSchedule , \n sites: $sites, \n mode: $mode, \n endTime: $endTime,\n semesterVisibility:false,\n thesisFactor: $thesisFactor,\n power: $power,\n visPower: $visPower,\n metPower: $metPower,\n whaPower: $whaPower}\n ) {\n nightPlans{\n nightTimeline{\n nightIndex\n timeEntriesBySite{\n site,\n timeEntries{\n startTimeSlots,\n event,\n plan{\n startTime,\n visits{\n obsId,\n endTime,\n altitude,\n atomEndIdx,\n atomStartIdx,\n startTime,\n instrument,\n score,\n obsClass,\n completion,\n peakScore,\n },\n nightStats{\n timeloss,\n planScore,\n timeloss,\n nToos,\n completionFraction,\n }\n }\n }\n }\n }\n },\n plansSummary\n }\n }\n"];
export function graphql(source: "\n query schedule($startTime: String!,\n $endTime: String!,\n $sites: Sites!,\n $mode: SchedulerModes!,\n $numNightsToSchedule: Int!,\n $thesisFactor: Float,\n $power: Int,\n $metPower: Float,\n $visPower: Float,\n $whaPower: Float ) {\n schedule(\n newScheduleInput: {\n startTime: $startTime, \n numNightsToSchedule: $numNightsToSchedule , \n sites: $sites, \n mode: $mode, \n endTime: $endTime,\n semesterVisibility:false,\n thesisFactor: $thesisFactor,\n power: $power,\n visPower: $visPower,\n metPower: $metPower,\n whaPower: $whaPower}\n ) {\n nightPlans{\n nightTimeline{\n nightIndex\n timeEntriesBySite{\n site,\n mornTwilight,\n eveTwilight,\n timeEntries{\n startTimeSlots,\n event,\n plan{\n startTime,\n visits{\n obsId,\n endTime,\n altitude,\n atomEndIdx,\n atomStartIdx,\n startTime,\n instrument,\n score,\n obsClass,\n completion,\n peakScore,\n },\n nightStats{\n timeloss,\n planScore,\n timeloss,\n nToos,\n completionFraction,\n }\n }\n }\n }\n }\n },\n plansSummary\n }\n }\n"): (typeof documents)["\n query schedule($startTime: String!,\n $endTime: String!,\n $sites: Sites!,\n $mode: SchedulerModes!,\n $numNightsToSchedule: Int!,\n $thesisFactor: Float,\n $power: Int,\n $metPower: Float,\n $visPower: Float,\n $whaPower: Float ) {\n schedule(\n newScheduleInput: {\n startTime: $startTime, \n numNightsToSchedule: $numNightsToSchedule , \n sites: $sites, \n mode: $mode, \n endTime: $endTime,\n semesterVisibility:false,\n thesisFactor: $thesisFactor,\n power: $power,\n visPower: $visPower,\n metPower: $metPower,\n whaPower: $whaPower}\n ) {\n nightPlans{\n nightTimeline{\n nightIndex\n timeEntriesBySite{\n site,\n mornTwilight,\n eveTwilight,\n timeEntries{\n startTimeSlots,\n event,\n plan{\n startTime,\n visits{\n obsId,\n endTime,\n altitude,\n atomEndIdx,\n atomStartIdx,\n startTime,\n instrument,\n score,\n obsClass,\n completion,\n peakScore,\n },\n nightStats{\n timeloss,\n planScore,\n timeloss,\n nToos,\n completionFraction,\n }\n }\n }\n }\n }\n },\n plansSummary\n }\n }\n"];

/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
Expand Down
Loading

0 comments on commit 87cfdd0

Please sign in to comment.