Index: /branches/eam_branches/ipp-20230313/ippMonitor/Makefile.in
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/Makefile.in	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/Makefile.in	(revision 42751)
@@ -88,4 +88,7 @@
 $(DESTWWW)/skycoverage.php \
 $(DESTWWW)/ganglia.php \
+$(DESTWWW)/scatterPlotPointing.php \
+$(DESTWWW)/scatterPlotAirmassMcal.php \
+$(DESTWWW)/scatterPlotDataQuality.php \
 $(DESTWWW)/loader.js
 
Index: /branches/eam_branches/ipp-20230313/ippMonitor/def/addRunRun.d
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/def/addRunRun.d	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/def/addRunRun.d	(revision 42751)
@@ -13,5 +13,4 @@
 FIELD addRun.stage_id,     5, %d,     stageID
 FIELD addRun.stage_extra1, 5, %d,     stageExtra1
-#FIELD addRun.add_id,       5, %d,     addID
 FIELD addRun.state,        5, %s,     state
 FIELD addRun.workdir,      5, %s,     workdir
@@ -20,5 +19,4 @@
 FIELD addRun.data_group,   5, %s,     data_group
 FIELD addRun.dvodb,        5, %s,     dvodb
-FIELD addRun.note,         5, %s,     note
 FIELD addRun.image_only,   5, %d,   image_only
 FIELD addRun.minidvodb,    5, %d,     minidvodb
@@ -26,2 +24,3 @@
 FIELD addRun.minidvodb_name,  5, %s,     minidvodb_name
 FIELD addRun.minidvodb_host,  5, %s,     minidvodb_host
+FIELD addRun.note,         5, %s,     note
Index: /branches/eam_branches/ipp-20230313/ippMonitor/def/minidvodbRun.d
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/def/minidvodbRun.d	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/def/minidvodbRun.d	(revision 42751)
@@ -1,4 +1,3 @@
 TABLE minidvodbRun 
-#TABLE minidvodbRun LEFT JOIN (SELECT count(*) AS addnum, minidvodb_name FROM addRun GROUP BY minidvodb_name) AS sub ON sub.minidvodb_name = minidvodbRun.minidvodb_name
 TITLE minidvodb Runs
 FILE  minidvodbRun.php
Index: /branches/eam_branches/ipp-20230313/ippMonitor/def/minidvodbRun_num.d
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/def/minidvodbRun_num.d	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/def/minidvodbRun_num.d	(revision 42751)
@@ -1,3 +1,2 @@
-#TABLE minidvodbRun 
 TABLE minidvodbRun LEFT JOIN (SELECT count(*) AS addnum, minidvodb_name FROM addRun GROUP BY minidvodb_name) AS sub ON sub.minidvodb_name = minidvodbRun.minidvodb_name
 TITLE minidvodb Runs
@@ -17,5 +16,5 @@
 #FIELD minidvodbRun.mergedvodb_path,          25, %s,     mergedvodb_path
 FIELD state,          5, %s,    State
+FIELD creation_date,        5, %T,     epoch
 FIELD addnum,                          5, %d,     addnum
-FIELD creation_date,        5, %T,     epoch
 
Index: /branches/eam_branches/ipp-20230313/ippMonitor/raw/czartool_labels.php
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/raw/czartool_labels.php	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/raw/czartool_labels.php	(revision 42751)
@@ -89,5 +89,5 @@
         "pstamp",
         "registration",
-        "stack",
+//        "stack",
         "stdscience",
         "summitcopy");
@@ -134,5 +134,4 @@
 }
 
-
 $debug = 0;
 $table = "<table bgcolor=\"#FFFFFF\" width=\"100%\" align=\"middle\" border=\"1\" cellspacing=\"0\" cellpadding=\"4\" style=\"font-size:80%\">\n";
@@ -183,8 +182,5 @@
 echo "<table border=\"0\">";
 // timer begin for main page
-$time = microtime();
-$time = explode(' ', $time);
-$time = $time[1] + $time[0];
-$mainstart = $time;
+$mainstart = microtime(true);
 
 # headers
@@ -210,4 +206,5 @@
 $hsttime1 = date("Y-m-d H:i:s", strtotime("$lastUpdateTime"));
 $utctime1 = gmdate("Y-m-d H:i:s", strtotime("$lastUpdateTime"));
+$mjdday = getMJD();
 
 echo "<br>";
@@ -249,5 +246,5 @@
           <td>".getNightlyScienceStatus($czardb, $proj)."</td></tr>"; 
 echo "<tr><td>Czardb last update time</td> 
-          <td> $hsttime1 (HST), $utctime1 (UTC)</td></tr>";
+          <td> $hsttime1 (HST), $utctime1 (UTC), $mjdday (MJD)</td></tr>";
 echo "</table><br>";
 
@@ -258,103 +255,87 @@
 # XXX EAM : 2017.09.17 : debugging slowness
 # CCL : 2019.11.09 : debugging slowness
-//createSummitDataTable($projectdb); // this is slow because of the join between summitExp and rawExp, but not the major one
-createSummitDataTable2($projectdb, $pass, $proj); // this is slow because of the join between summitExp and rawExp, but not the major one
-
-createChunkDataTable($projectdb);  // this is another part for slowness during nightly processing
-
-createDatesTable($czardb, $proj); 
+createSummitDataTable2($projectdb, $pass, $proj, $debug); // this is slow because of the join between summitExp and rawExp, but not the major one
+
+createChunkDataTable($projectdb, $debug);  // this is another part for slowness during nightly processing
+
+// createDatesTable($czardb, $proj); what is this for?
 
 // Database status
-// timer begin for Database status
-$time = microtime();
-$time = explode(' ', $time);
-$time = $time[1] + $time[0];
-$start = $time;
-
 echo $table;
-echo "<tr>";
-createTableTitle("Database status (update fix log <a href=\"http://svn.pan-starrs.ifa.hawaii.edu/trac/ipp/wiki/Replication_Issues\"><font color=\"blue\">here</a>)", 2);
-  
-echo "<tr>";
-createTableColumnHeader("Database");
-createTableColumnHeader("Status (sec behind master)");
-// gpc dbs
-showDatabaseStatus($HOST_GPC1, $USER_GPC1, $PASSWORD_GPC1, $LABEL_GPC1);
-showReplicationsStatus($REPL_HOST_GPC1, $REPL_USER_GPC1, $REPL_PASSWORD_GPC1, $REPL_LABEL_GPC1);
-showReplicationsStatus($REPL_HOST_GPC1_SECONDARY, $REPL_USER_GPC1_SECONDARY, $REPL_PASSWORD_GPC1_SECONDARY, $REPL_LABEL_GPC1_SECONDARY);
-showReplicationsStatus($REPL_HOST_GPC1_TERTIARY, $REPL_USER_GPC1_TERTIARY, $REPL_PASSWORD_GPC1_TERTIARY, $REPL_LABEL_GPC1_TERTIARY);
-// nebulous dbs
-showDatabaseStatus($HOST_NEBULOUS, $USER_NEBULOUS, $PASSWORD_NEBULOUS, $LABEL_NEBULOUS);
-//showReplicationsStatus($REPL_HOST_NEBULOUS, $REPL_USER_NEBULOUS, $REPL_PASSWORD_NEBULOUS, $REPL_LABEL_NEBULOUS);
-showReplicationsStatus($REPL_HOST_NEBULOUS_SECONDARY, $REPL_USER_NEBULOUS_SECONDARY, $REPL_PASSWORD_NEBULOUS_SECONDARY, $REPL_LABEL_NEBULOUS_SECONDARY);
-showReplicationsStatus($REPL_HOST_NEBULOUS_TERTIARY, $REPL_USER_NEBULOUS_TERTIARY, $REPL_PASSWORD_NEBULOUS_TERTIARY, $REPL_LABEL_NEBULOUS_TERTIARY);
-showReplicationsStatus($REPL_HOST_NEBULOUS_QUATERNARY, $REPL_USER_NEBULOUS_QUATERNARY, $REPL_PASSWORD_NEBULOUS_QUATERNARY, $REPL_LABEL_NEBULOUS_QUATERNARY);
-// other dbs
-showDatabaseStatus($HOST_PSTAMP, $USER_PSTAMP, $PASSWORD_PSTAMP, $LABEL_PSTAMP);
-showReplicationsStatus($REPL_HOST_DATASTORE, $REPL_USER_DATASTORE, $REPL_PASSWORD_DATASTORE, $REPL_LABEL_DATASTORE);
-
-// timer finished
-echo "<tr><th colspan=2>";
-$time = microtime();
-$time = explode(' ', $time);
-$time = $time[1] + $time[0];
-$finish = $time;
-$total_time = round(($finish - $start), 3);
-echo "loading in $total_time seconds.";
-echo "</th></tr>";
+    // timer begin
+    $start = microtime(true);
+    echo "<tr>";
+    createTableTitle("Database status (update fix log <a href=\"http://svn.pan-starrs.ifa.hawaii.edu/trac/ipp/wiki/Replication_Issues\"><font color=\"blue\">here</a>)", 2);
+      
+    echo "<tr>";
+    createTableColumnHeader("Database");
+    createTableColumnHeader("Status (sec behind master)");
+    // gpc dbs
+    showDatabaseStatus($HOST_GPC1, $USER_GPC1, $PASSWORD_GPC1, $LABEL_GPC1);
+    showReplicationsStatus($REPL_HOST_GPC1, $REPL_USER_GPC1, $REPL_PASSWORD_GPC1, $REPL_LABEL_GPC1);
+    showReplicationsStatus($REPL_HOST_GPC1_SECONDARY, $REPL_USER_GPC1_SECONDARY, $REPL_PASSWORD_GPC1_SECONDARY, $REPL_LABEL_GPC1_SECONDARY);
+    showReplicationsStatus($REPL_HOST_GPC1_TERTIARY, $REPL_USER_GPC1_TERTIARY, $REPL_PASSWORD_GPC1_TERTIARY, $REPL_LABEL_GPC1_TERTIARY);
+    // nebulous dbs
+    showDatabaseStatus($HOST_NEBULOUS, $USER_NEBULOUS, $PASSWORD_NEBULOUS, $LABEL_NEBULOUS);
+    //showReplicationsStatus($REPL_HOST_NEBULOUS, $REPL_USER_NEBULOUS, $REPL_PASSWORD_NEBULOUS, $REPL_LABEL_NEBULOUS);
+    showReplicationsStatus($REPL_HOST_NEBULOUS_SECONDARY, $REPL_USER_NEBULOUS_SECONDARY, $REPL_PASSWORD_NEBULOUS_SECONDARY, $REPL_LABEL_NEBULOUS_SECONDARY);
+    showReplicationsStatus($REPL_HOST_NEBULOUS_TERTIARY, $REPL_USER_NEBULOUS_TERTIARY, $REPL_PASSWORD_NEBULOUS_TERTIARY, $REPL_LABEL_NEBULOUS_TERTIARY);
+    showReplicationsStatus($REPL_HOST_NEBULOUS_QUATERNARY, $REPL_USER_NEBULOUS_QUATERNARY, $REPL_PASSWORD_NEBULOUS_QUATERNARY, $REPL_LABEL_NEBULOUS_QUATERNARY);
+    // other dbs
+    showDatabaseStatus($HOST_PSTAMP, $USER_PSTAMP, $PASSWORD_PSTAMP, $LABEL_PSTAMP);
+    showReplicationsStatus($REPL_HOST_DATASTORE, $REPL_USER_DATASTORE, $REPL_PASSWORD_DATASTORE, $REPL_LABEL_DATASTORE);
+    
+    // end time
+    echo "<tr><th colspan=2>";
+    $total_time = round((microtime(true) - $start), 3);
+    echo "loading in $total_time seconds.";
+    echo "</th></tr>";
 echo "</table><br>";
 
 
 // critical machines status
-// timer begin for critical machines
-$time = microtime();
-$time = explode(' ', $time);
-$time = $time[1] + $time[0];
-$start = $time;
-
-$PingStatus = "<font style=\"BACKGROUND-COLOR: yellow\"  color=\"red\">DOWN</font>";
 echo $table;
-echo "<tr>";
-createTableTitle("Critical machine status", 3);
-
-echo "<tr>";
-createTableColumnHeader("Hostname");
-createTableColumnHeader("Status");
-createTableColumnHeader("Loading time");
-showPingStatus($HOST_GATEWAY, $LABEL_GATEWAY);
-showPingStatus($HOST_GATEWAY_SECONDARY, $LABEL_GATEWAY_SECONDARY);
-showPingStatus($HOST_PROXY, $LABEL_PROXY);
-showPingStatus($HOST_APACHE1, $LABEL_APACHE1);
-showPingStatus($HOST_APACHE2, $LABEL_APACHE2);
-showPingStatus($HOST_APACHE3, $LABEL_APACHE3);
-showPingStatus($HOST_APACHE4, $LABEL_APACHE4);
-showPingStatus($HOST_APACHE5, $LABEL_APACHE5);
-showPingStatus($HOST_APACHE6, $LABEL_APACHE6);
-showPingStatus($HOST_APACHE_BACKUP1, $LABEL_APACHE_BACKUP1);
-showPingStatus($HOST_APACHE_BACKUP2, $LABEL_APACHE_BACKUP2);
-showPingStatus($HOST_HOME, $LABEL_HOME);
-showPingStatus($HOST_HOME_BACKUP, $LABEL_HOME_BACKUP);
-showPingStatus($HOST_NAGIOS, $LABEL_NAGIOS);
-showPingStatus($HOST_SVN, $LABEL_SVN);
-showPingStatus($HOST_CONFLUENCE, $LABEL_CONFLUENCE);
-showPingStatus($HOST_MAILMAN, $LABEL_MAILMAN);
-//  echo "<td>ippc70 (apache node) <td> $PingStatus <td> 0 seconds ";  // comment out if ippc70 is back
-// timer finished
-echo "<tr><th colspan=3>";
-$time = microtime();
-$time = explode(' ', $time);
-$time = $time[1] + $time[0];
-$finish = $time;
-$total_time = round(($finish - $start), 3);
-echo "loading in $total_time seconds.";
-echo "</th></tr>";
+    // start time
+    $start = microtime(true);
+    
+    $PingStatus = "<font style=\"BACKGROUND-COLOR: yellow\"  color=\"red\">DOWN</font>";
+
+    echo "<tr>";
+    createTableTitle("Critical machine status", 3);
+    
+    echo "<tr>";
+    createTableColumnHeader("Hostname");
+    createTableColumnHeader("Status");
+    createTableColumnHeader("Loading time");
+    showPingStatus($HOST_GATEWAY, $LABEL_GATEWAY);
+    showPingStatus($HOST_GATEWAY_SECONDARY, $LABEL_GATEWAY_SECONDARY);
+    showPingStatus($HOST_PROXY, $LABEL_PROXY);
+    showPingStatus($HOST_APACHE1, $LABEL_APACHE1);
+    showPingStatus($HOST_APACHE2, $LABEL_APACHE2);
+    showPingStatus($HOST_APACHE3, $LABEL_APACHE3);
+    showPingStatus($HOST_APACHE4, $LABEL_APACHE4);
+    showPingStatus($HOST_APACHE5, $LABEL_APACHE5);
+    showPingStatus($HOST_APACHE6, $LABEL_APACHE6);
+    showPingStatus($HOST_APACHE_BACKUP1, $LABEL_APACHE_BACKUP1);
+    showPingStatus($HOST_APACHE_BACKUP2, $LABEL_APACHE_BACKUP2);
+    showPingStatus($HOST_HOME, $LABEL_HOME);
+    showPingStatus($HOST_HOME_BACKUP, $LABEL_HOME_BACKUP);
+    showPingStatus($HOST_NAGIOS, $LABEL_NAGIOS);
+    showPingStatus($HOST_SVN, $LABEL_SVN);
+    showPingStatus($HOST_CONFLUENCE, $LABEL_CONFLUENCE);
+    showPingStatus($HOST_MAILMAN, $LABEL_MAILMAN);
+
+    // end time
+    echo "<tr><th colspan=3>";
+    $total_time = round((microtime(true) - $start), 3);
+    echo "loading in $total_time seconds.";
+    echo "</th></tr>";
 echo "</table><br>";
 
-createServersTable($pass, $proj,$selectedMode,$czardb, $servers, $selectedLabel, $selectedStage, $plotType); // this was the major slowness part due to large table in czardb
-
-# pantasks server status, if requested
-if ($selectedServer && !$serverCmd) showServerStatus($selectedServer, $proj);
-
-#2nd table column for space
+createServersTable($pass, $proj,$selectedMode,$czardb, $servers, $selectedLabel, $selectedStage, $plotType); 
+    # pantasks server status, if requested
+    if ($selectedServer && !$serverCmd) showServerStatus($selectedServer, $proj);
+
+#2nd table column empty contnets
 echo "<td style=height:200px;width: 10px;text-align:top;\"><br>";
 
@@ -362,41 +343,41 @@
 echo "<td style=height:200px;width:600px;text-align:top;\"><br>";
 # plots
-if ($selectedStage == "all_stages" & $selectedLabel == "all") { 
-   # with all stages and all labels, the rate query is too slow so I use the old method until it get improved. CCL 20210117
-   # gnuplots
-   # time series plot
-   echo "<img src=\"czartool_getplot.php?mode=$selectedMode&type=t&label=$selectedLabel&proj=$proj&stage=$selectedStage&plottype=linear\"><br><br>";
-   echo "<img src=\"czartool_getplot.php?mode=$selectedMode&type=t&label=$selectedLabel&proj=$proj&stage=$selectedStage&plottype=log\"><br><br>";
-   # rate series plot
-   echo "<img src=\"czartool_getplot.php?mode=$selectedMode&type=rt&label=$selectedLabel&proj=$proj&stage=$selectedStage&plottype=linear\"><br><br>";
-   #for dev version
-   # google chart
-   # time series plot
-   #echo Gettimeseries($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
-   # rate series plot
-   #echo Getrate($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
+if ($selectedStage == "all_stages" && $selectedLabel == "all") {
+    // Use old method with gnuplots as the rate query is slow with all stages and labels
+    displayImage("t", $selectedMode, $selectedLabel, $proj, $selectedStage, "linear");
+    displayImage("t", $selectedMode, $selectedLabel, $proj, $selectedStage, "log");
+    displayImage("rt", $selectedMode, $selectedLabel, $proj, $selectedStage, "linear");
+
+    // Uncomment for dev version with Google Charts
+    // echo Gettimeseries($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
+    //echo Getrate($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
 } else {
-   # google chart
-   # time series plot
-   echo Gettimeseries($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
-   # rate series plot
-   echo Getrate($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
+    // Use Google Charts for specific stage and label
+    echo Gettimeseries($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
+    echo Getrate($czardb, $selectedMode, $selectedLabel, $proj, $selectedStage);
+}
+
+// Helper function to generate image tags for plots
+function displayImage($type, $mode, $label, $proj, $stage, $plottype) {
+    $src = "czartool_getplot.php?mode=" . urlencode($mode) .
+           "&type=" . urlencode($type) .
+           "&label=" . urlencode($label) .
+           "&proj=" . urlencode($proj) .
+           "&stage=" . urlencode($stage) .
+           "&plottype=" . urlencode($plottype);
+    echo "<img src=\"$src\"><br><br>";
 }
 
 # data quality timeseries
-echo getDataQuality($projectdb);
+echo getDataQuality2($projectdb); // new version of data quality plots
+
 # storage timeseries
 echo getSpaces($czardb);
 # storage plot
-echo getHosts($czardb);
+ echo getHosts($czardb);
 
 # timer for main page end
 echo "<tr><th colspan=3>";
-$time = microtime();
-$time = explode(' ', $time);
-$time = $time[1] + $time[0];
-$finish = $time;
-$total_time = round(($finish - $mainstart), 3);
-echo "overall loading in $total_time seconds.";
+echo "overall loading in " . round((microtime(true) - $mainstart), 3) . " seconds.";
 echo "</th></tr>";
 echo "</table>";
@@ -457,25 +438,28 @@
 #
 ###########################################################################
-function createChunkDataTable($projectdb) {
+function createChunkDataTable($projectdb, $debug) {
 
     // timer start
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $start = $time;
+    $start = microtime(true);
 
     // function begin
     #First find the reference exposure ID to speed up the subsequent queries
+    $mjdDay  = getMJD();
+    $expname = "o{$mjdDay}%";
+
     $date = gmdate("Y-m-d");
-    $sql = "SELECT MAX(exp_id) FROM rawExp WHERE dateobs >= date_sub('$date', interval 20 day) AND dateobs <= date_sub('$date', interval 10 day)";
+    $sql = "SELECT MIN(exp_id) FROM rawExp WHERE exp_name like '$expname' ";
+    if ($debug) {echo "$sql<br>";}
     $qry = $projectdb->query($sql);
+
     if (dberror($qry)) {
-        print "*** WARNING: no data in period 10-20 days before requested date (query will be slower) **\n";
-        $refExpID = 0; 
-    }
-    $qry->fetchInto($refExpID);
-    if ($refExpID[0] = 'NULL') {
-        $refExpID[0] = 0;
-    }
+        echo "*** WARNING: No data for tonight **\n";
+        $refExpID = 0;
+    } else {
+        $qry->fetchInto($refExpID);
+        $refExpID = isset($refExpID[0]) ? $refExpID[0] : 0;
+    }
+    // Print the result of the query
+    if ($debug) {echo "The first exp_id of tonight is: $refExpID<br>";}
 
     #do a query of raw/chip/cam/warp counts for this night, split by chunk. 
@@ -485,7 +469,7 @@
     $query .= "    count(if(rawExp.comment LIKE '%visit 2%',1,NULL)) AS Nvis2,count(if(rawExp.comment LIKE '%visit 3%',1,NULL)) AS Nvis3,";
     $query .= "    count(if(rawExp.comment LIKE '%visit 4%',1,NULL)) AS Nvis4, count(if(camProcessedExp.sigma_ra <= 5 AND camProcessedExp.sigma_dec <= 5 AND camProcessedExp.quality = 0,1,NULL)) AS Ncamgood,";
-    $query .= "    count(if(camProcessedExp.sigma_ra > 5 OR camProcessedExp.sigma_dec > 5 OR camProcessedExp.quality > 0,1,NULL)) AS Ncambad";
+    $query .= "    count(if(camProcessedExp.fwhm_major > 12 OR camProcessedExp.sigma_ra > 5 OR camProcessedExp.sigma_dec > 5 OR camProcessedExp.quality > 0,1,NULL)) AS Ncambad";
     $query .= "    FROM rawExp LEFT JOIN chipRun USING (exp_id) LEFT JOIN camRun USING (chip_id) JOIN camProcessedExp USING (cam_id) LEFT JOIN fakeRun USING (cam_id) LEFT JOIN warpRun USING (fake_id)";
-    $query .= "    WHERE dateobs like '$date%' AND exp_id > $refExpID[0] AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%'";
+    $query .= "    WHERE exp_name like '$expname' AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%'";
     $query .= "    AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
     $query .= "    GROUP BY chunk ORDER BY dateobs) as suba ";
@@ -495,11 +479,13 @@
     $query .= "      (SELECT substr(comment, 1, position(' ' in comment)) AS chunk,count(warpSkyfile.quality) AS Nwarpskycell,count(if(warpSkyfile.quality > 0,1,NULL)) AS Nwarpskycellbad";
     $query .= "      FROM rawExp LEFT JOIN chipRun USING (exp_id) LEFT JOIN camRun USING (chip_id) LEFT JOIN fakeRun USING (cam_id) LEFT JOIN warpRun USING (fake_id) JOIN warpSkyfile USING (warp_id)";
-    $query .= "      WHERE dateobs like '$date%' AND exp_id > $refExpID[0] AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%'";
+    $query .= "      WHERE exp_name like '$expname' AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%'";
     $query .= "      AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
     $query .= "      GROUP BY exp_name) as subc";
     $query .= "    GROUP BY chunk) AS subb ";
     $query .= "ON suba.chunk=subb.chunk";
-
+ 
+    if ($debug) {echo "$query<br>";}
     $qry = $projectdb->query($query);
+
     if (dberror($qry)) {
         echo "<b>error querying SQL table</b><br>\n";
@@ -512,5 +498,6 @@
     echo $table;
     echo "<tr>";
-    createTableTitle("Status of last night's chunks", 10);
+    $mjdday = getMJD();
+    createTableTitle("Status of night $mjdday chunks", 10);
     echo "<tr>";
     createTableColumnHeader("Chunk");
@@ -556,7 +543,9 @@
         $query1 = "SELECT suba.chunk, SUM(IF(suba.Nvisits = 2,1,NULL)) as totvis2, SUM(IF(suba.Nvisits = 3 OR suba.Nvisits = 4,2,NULL)) as totvis34 FROM";
         $query1 .= "    (SELECT substr(comment, 1, position(' ' in comment)) AS chunk,count(distinct(comment)) AS Nvisits FROM";
-        $query1 .= "    rawExp LEFT JOIN chipRun USING (exp_id) LEFT JOIN camRun USING (chip_id) WHERE dateobs like '$date%'";
-        $query1 .= "    AND exp_id > $refExpID[0] AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%' AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
+        $query1 .= "    rawExp LEFT JOIN chipRun USING (exp_id) LEFT JOIN camRun USING (chip_id) ";
+        $query1 .= "    WHERE exp_name like '$expname'";
+        $query1 .= "    AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%' AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
         $query1 .= "    AND substr(comment, 1, position(' ' in comment)) LIKE '$chunkname%' group by object) as suba group by chunk;";
+
         $qry1 = $projectdb->query($query1);
         while ($qry1->fetchInto($row)) {$NexpWWdiff = $row[1] + $row[2];}
@@ -565,5 +554,6 @@
         $query2 = "     SELECT diff_id,warp1,stack1,warp2,stack2 FROM ";
         $query2 .= "           diffInputSkyfile JOIN warpRun ON (warp1=warp_id OR warp2=warp_id) JOIN fakeRun USING (fake_id) JOIN camRun USING (cam_id) JOIN camProcessedExp USING (cam_id) JOIN chipRun USING (chip_id) JOIN rawExp USING (exp_id)";
-        $query2 .= "           WHERE rawExp.dateobs LIKE '$date%' AND exp_id > $refExpID[0] AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%' AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%')";
+        $query2 .= "           WHERE exp_name like '$expname'";
+        $query2 .= "           AND exp_type = 'OBJECT' AND rawExp.comment like '%visit%' AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%')";
         $query2 .= "            AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL' AND substr(comment, 1, position(' ' in comment)) LIKE '$chunkname%' GROUP By diff_id";
         $qry2 = $projectdb->query($query2);
@@ -670,9 +660,9 @@
         $query .= " JOIN camRun USING (chip_id)";
         $query .= " JOIN camProcessedExp USING (cam_id)";
-        $query .= " WHERE dateobs LIKE '$date%'";
-        $query .= " AND exp_id > $refExpID[0]"; 
+        //$query .= " WHERE dateobs LIKE '$date%' AND exp_id > $refExpID"; 
+        $query .= " WHERE exp_name like '$expname'";
         $query .= " AND exp_type = 'OBJECT'";
         $query .= " AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
-        $query .= " AND (camProcessedExp.quality > 0 OR camProcessedExp.sigma_ra > 5 OR camProcessedExp.sigma_dec > 5)";
+        $query .= " AND (camProcessedExp.fwhm_major > 12 OR camProcessedExp.quality > 0 OR camProcessedExp.sigma_ra > 5 OR camProcessedExp.sigma_dec > 5)";
         $query .= " ORDER BY comment";
 
@@ -710,5 +700,5 @@
         $query = "SELECT exp_name,warp_id,count(warpSkyfile.quality) AS Nwarpskycell,count(if(warpSkyfile.quality > 0,1,NULL)) AS Nwarpskycellbad, comment";
         $query .= "      FROM rawExp LEFT JOIN chipRun USING (exp_id) LEFT JOIN camRun USING (chip_id) LEFT JOIN fakeRun USING (cam_id) LEFT JOIN warpRun USING (fake_id) JOIN warpSkyfile USING (warp_id)";
-        $query .= "      WHERE dateobs like '$date%' AND exp_id > $refExpID[0]";
+        $query .= "      WHERE exp_name like '$expname'";
         $query .= "      AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
         $query .= "      GROUP BY exp_name ORDER BY comment";
@@ -747,8 +737,10 @@
         $query = "     SELECT diff_id,warp1,stack1,warp2,stack2,exp_name,comment FROM ";
         $query .= "           diffInputSkyfile JOIN warpRun ON (warp1=warp_id OR warp2=warp_id) JOIN fakeRun USING (fake_id) JOIN camRun USING (cam_id) JOIN camProcessedExp USING (cam_id) JOIN chipRun USING (chip_id) JOIN rawExp USING (exp_id)";
-        $query .= "           WHERE rawExp.dateobs LIKE '$date%' AND exp_id > $refExpID[0] AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
+        $query .= "           WHERE exp_name like '$expname'";
+        $query .= "           AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
         $query .= "           GROUP By diff_id";
+        if ($debug) {echo "$query<br>";}
+
         $qry1 = $projectdb->query($query);
-
         while ($qry1->fetchInto($row)) {
             #distinguish between WW and WS diffs based on stack2
@@ -811,6 +803,5 @@
     $query .= " JOIN chipRun USING (exp_id)";
     $query .= " JOIN camRun USING (chip_id)";
-    $query .= " WHERE dateobs LIKE '$date%'";
-    $query .= " AND exp_id > $refExpID[0]"; 
+    $query .= " WHERE exp_name like '$expname'";
     $query .= " AND exp_type = 'OBJECT'";
     $query .= " AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
@@ -826,6 +817,6 @@
             $query .= " JOIN chipRun USING (exp_id)";
             $query .= " JOIN camRun USING (chip_id)";
-            $query .= " WHERE dateobs LIKE '$date%' AND comment LIKE '$row[1]'";
-            $query .= " AND exp_id > $refExpID[0]"; 
+            $query .= " WHERE exp_name like '$expname'";
+            $query .= " AND comment LIKE '$row[1]'";
             $query .= " AND exp_type = 'OBJECT'";
             $query .= " AND (obs_mode LIKE '%SS%' OR obs_mode LIKE '%BRIGHT%') AND obs_mode NOT LIKE 'ENGINEERING' AND obs_mode NOT LIKE 'MANUAL'";
@@ -863,13 +854,9 @@
 
 
-    // timer finished
+    // End timer
     echo "<tr><th colspan=10>";
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $finish = $time;
-    $total_time = round(($finish - $start), 3);
-    echo "loading in $total_time seconds.";
-    $start= $finish;
+    $total_time = round(microtime(true) - $start, 3);
+    echo "<center>loading in $total_time seconds<br></center>";
+
     echo "</th></tr>";
     echo "</table></br>";
@@ -914,9 +901,7 @@
         $selectedState, $selectedLabel, $selectedStage, $plotType) {
 
-    // timer start
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $start = $time;
+    // Start timer
+    $start = microtime(true);
+
 
     // function begin
@@ -1010,6 +995,6 @@
             }
           }
-      // echo "getStateAndFaults $db, $thisLabel, $proj, $selectedState, $stage, $str, $anyFaults<br>";
       getStateAndFaults($db, $thisLabel, $proj, $selectedState, $stage, $str, $anyFaults);
+      //echo "getStateAndFaults $db, $thisLabel, $proj, $selectedState, $stage, $str, $anyFaults<br>";
 
       $cellcolor = 0;
@@ -1045,13 +1030,9 @@
     echo "</tr>\n";
 
-    // timer finished
+    // End timer
     echo "<tr><th colspan=11>";
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $finish = $time;
-    $total_time = round(($finish - $start), 3);
-    echo "loading in $total_time seconds.";
-    $start= $finish;
+    $total_time = round(microtime(true) - $start, 3);
+    echo "<center>loading plot in $total_time seconds<br></center>";
+
     echo "</th></tr>";
     echo "</table><br>";
@@ -1204,8 +1185,5 @@
 
     // timer start
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $start = $time;
+    $start = microtime(true);
 
     // function begin
@@ -1223,13 +1201,8 @@
 
     // timer finished
-#    echo "<tr><th colspan=11>";
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $finish = $time;
-    $total_time = round(($finish - $start), 3);
-#    echo "loading in $total_time seconds.";
-    $start= $finish;
-#    echo "</th></tr>";
+    echo "<tr><th colspan=11>";
+    $total_time = round((microtime(true) - $start), 3);
+    echo "loading in $total_time seconds.";
+    echo "</th></tr>";
     echo "</table><br>";
 
@@ -1272,13 +1245,8 @@
 ###########################################################################
 function createServersTable($pass, $proj, $selectedMode, $db, $servers, $selectedLabel, $selectedStage, $plotType) {
-
-    // timer start
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $start = $time;
-
-    // function begin
-    // set up table columns
+    // Start the timer
+    $start = microtime(true);
+
+    // Display table header
     global $table;
     echo $table;
@@ -1286,14 +1254,18 @@
     createTableTitle("Pantasks server status", 3);
     echo "<tr>";
-    createTableColumnHeader("Server");
-    createTableColumnHeader("Alive?");
-    createTableColumnHeader("Running?");
+
+    // Define column headers in an array for flexibility
+    $columnHeaders = array("Server", "Alive?", "Running?");
+    foreach ($columnHeaders as $header) {
+        createTableColumnHeader($header);
+    }
     echo "</tr>\n";
 
     foreach ($servers as &$server) {
-
         getServerStatus($db,$proj, $server, $alive, $running);
 
         echo "<tr>\n";
+
+        // Generate the link once and pass it to the cell function
         $link = "czartool_labels.php?pass=".$pass
             ."&proj=".$proj
@@ -1304,19 +1276,15 @@
             ."&plottype=".$plotType;
 
+        // Display server row cells
         createFormattedTableCell(1, $link, $server, 0, 0);
         createFormattedTableCell(0, "", $alive ? "yes" : "NO", !$alive, 0);
         createFormattedTableCell(0, "", $running ? "yes" : "NO", !$running, 0);
+
         echo "</tr>\n";
     }
 
-    // timer finished
+    // Display loading time
     echo "<tr><th colspan=5>";
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $finish = $time;
-    $total_time = round(($finish - $start), 3);
-    echo "loading in $total_time seconds.";
-    $start= $finish;
+    echo "loading in " . round((microtime(true) - $start), 3) . " seconds.";
     echo "</th></tr>";
     echo "</table><br>\n";
@@ -1515,16 +1483,21 @@
 #
 ###########################################################################
-function createSummitDataTable2($projectdb, $pass, $proj) {
+function createSummitDataTable2($projectdb, $pass, $proj, $debug) {
 
     // timer start
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $start = $time;
-
-    // function begin
-    $date = gmdate("Y-m-d");
-    $datem1 = gmdate("Y-m-d",strtotime ( "-1 day") );
-    $datetime = gmdate("H:i:s");
+    $start = microtime(true);
+
+    // Define constants
+    $mjdDay = getMJD();
+    $expname = "%{$mjdDay}%";
+
+    $mjdDaym1 = $mjdDay - 1;
+    $expnamem1 = "%{$mjdDaym1}%";
+
+    $mjdDaym5 = $mjdDay - 5;
+    $expnamem5 = "o{$mjdDaym5}%";
+
+    $currentDate = gmdate("Y-m-d H:i:s");
+    $previousDate = gmdate("Y-m-d", strtotime("-1 day"));
 
     // set up the table
@@ -1533,27 +1506,41 @@
     echo $table;
     echo "<tr>";
-    createTableTitle("Data status tonight $date <br> current time $datetime (UTC)", 4);
+      createTableTitle("Data status for night $mjdDay  <br> current time UT: $currentDate", 4);
     echo "<tr>";
-
-    createTableColumnHeader("Exposure type");
-    createTableColumnHeader("<a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=summitExp\"><font color=\"blue\">summitExp status</font></a>");
-    createTableColumnHeader("<a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=downloadExp\"><font color=\"blue\">downloadExp status</font></a>");
-    createTableColumnHeader("<a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=rawExp\"><font color=\"blue\">rawExp </a>/
-                             <a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=newExp\"><font color=\"blue\"> newExp</font></a>");
-    $sql = "SELECT summitExp.exp_type,pzDownloadExp.state,rawExp.state,COUNT(*) FROM summitExp 
-            LEFT JOIN pzDownloadExp USING (summit_id) LEFT JOIN rawExp on summitExp.exp_name = rawExp.exp_name 
-            WHERE summitExp.dateobs like '$date%' group by summitExp.exp_type,pzDownloadExp.state,rawExp.state";
+      createTableColumnHeader("Exposure type");
+      createTableColumnHeader("<a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=summitExp\"><font color=\"blue\">summitExp status</font></a>");
+      createTableColumnHeader("<a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=downloadExp\"><font color=\"blue\">downloadExp status</font></a>");
+      createTableColumnHeader("<a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=rawExp\"><font color=\"blue\">rawExp </a>/
+                               <a href=\"czartool_labels.php?pass=".$pass."&proj=".$proj."&label=all&stage=newExp\"><font color=\"blue\"> newExp</font></a>");
+
+    $sql = "
+        SELECT sum_type, pzstate, rawstate, count(*), sum_exp, pz_exp, raw_exp 
+        FROM 
+          (SELECT summitExp.exp_type as sum_type, pzDownloadExp.state as pzstate, rawExp.state as rawstate, summitExp.exp_name as sum_exp, pzDownloadExp.exp_name as pz_exp, rawExp.exp_name as raw_exp
+           FROM summitExp
+           LEFT JOIN pzDownloadExp USING (summit_id)
+           LEFT JOIN rawExp ON summitExp.exp_name = rawExp.exp_name
+           WHERE summitExp.summit_id >= (
+               SELECT COALESCE(MIN(summit_id), 0) 
+               FROM summitExp 
+               WHERE exp_name LIKE '$expnamem5'
+            ) 
+            AND summitExp.exp_name LIKE '$expname' ORDER BY summitExp.dateobs desc) as sub 
+        GROUP BY sum_type, pzstate, rawstate";
+    if ($debug) {echo "$sql<br>";}
+
     $qry = $projectdb->query($sql);
     while ($qry->fetchInto($tmp)) {
-        if ($tmp[1] == NULL) { 
-          echo  "<tr><td>$tmp[0]<td> null <td> null <td bgcolor=\"yellow\"> <font color=\"red\">$tmp[3]";
+        list($expType, $downloadState, $rawState, $count, $summit_exp, $pz_exp, $raw_exp) = $tmp;
+        if ($downloadState == NULL) { 
+          echo  "<tr><td> $expType ($summit_exp) <td> loading imfiles <td> null <td bgcolor=\"yellow\"> <font color=\"red\">$count";
         } else {
-          if ($tmp[1] == 'run') { 
-            echo  "<tr><td>$tmp[0]<td> loading <td> null <td bgcolor=$columnHeaderColor> <font color=\"red\">$tmp[3]"; 
+          if ($downloadState == 'run') { 
+            echo  "<tr><td> $expType ($summit_exp) <td> summit_copy ($pz_exp) <td> saving ($pz_exp) <td bgcolor=$columnHeaderColor> <font color=\"red\">$count"; 
           } else {
-            if ($tmp[2] == NULL) { 
-              echo  "<tr><td>$tmp[0] <td> $tmp[1] <td> loading <td bgcolor=$columnHeaderColor> <font color=\"blue\">$tmp[3]";
+            if ($rawState == NULL) { 
+              echo  "<tr><td> $expType ($summit_exp) <td> $downloadState ($pz_exp) <td> registering ($pz_exp) <td bgcolor=$columnHeaderColor> <font color=\"blue\">$count";
             } else {
-              echo  "<tr><td>$tmp[0]<td> $tmp[1] <td> downloaded <td> $tmp[3]";
+              echo  "<tr><td> $expType ($summit_exp) <td> $downloadState ($pz_exp) <td> $rawState ($raw_exp) <td> $count";
             }
           }
@@ -1561,35 +1548,85 @@
     }
 
-    echo "<tr><th colspan=4>Last night $datem1 (UTC)";
-    $sql = "SELECT summitExp.exp_type,pzDownloadExp.state,rawExp.state,COUNT(*) FROM summitExp 
-            LEFT JOIN pzDownloadExp USING (summit_id) LEFT JOIN rawExp on summitExp.exp_name = rawExp.exp_name 
-            WHERE summitExp.dateobs like '$datem1%' group by summitExp.exp_type,pzDownloadExp.state,rawExp.state";
+    echo "<tr><th colspan=4>Last night $previousDate (UTC), $mjdDaym1 (MJD)";
+    $sql = "
+        SELECT sum_type, pzstate, rawstate, count(*), sum_exp, pz_exp, raw_exp 
+        FROM 
+          (SELECT summitExp.exp_type as sum_type, pzDownloadExp.state as pzstate, rawExp.state as rawstate, summitExp.exp_name as sum_exp, pzDownloadExp.exp_name as pz_exp, rawExp.exp_name as raw_exp
+           FROM summitExp
+           LEFT JOIN pzDownloadExp USING (summit_id)
+           LEFT JOIN rawExp ON summitExp.exp_name = rawExp.exp_name
+           WHERE summitExp.summit_id >= (
+               SELECT COALESCE(MIN(summit_id), 0) 
+               FROM summitExp 
+               WHERE exp_name LIKE '$expnamem5'
+            ) 
+            AND summitExp.exp_name LIKE '$expnamem1' ORDER BY summitExp.dateobs desc) as sub 
+        GROUP BY sum_type, pzstate, rawstate";
+    // $sql = "
+    //     SELECT summitExp.exp_type, pzDownloadExp.state, rawExp.state, COUNT(*)
+    //     FROM summitExp
+    //     LEFT JOIN pzDownloadExp USING (summit_id)
+    //     LEFT JOIN rawExp ON summitExp.exp_name = rawExp.exp_name
+    //     WHERE summitExp.summit_id >= (
+    //         SELECT COALESCE(MIN(summit_id), 0) 
+    //         FROM summitExp 
+    //         WHERE exp_name LIKE '$expnamem5'
+    //     ) 
+    //     AND summitExp.exp_name LIKE '$expnamem1'
+    //     GROUP BY summitExp.exp_type, pzDownloadExp.state, rawExp.state";
+    if ($debug) {echo "$sql<br>";}
+
     $qry = $projectdb->query($sql);
     while ($qry->fetchInto($tmp)) {
-        if ($tmp[1] == NULL) { 
-          echo  "<tr><td>$tmp[0]<td> null <td> null <td bgcolor=\"yellow\"> <font color=\"red\">$tmp[3]";
+        list($expType, $downloadState, $rawState, $count, $summit_exp, $pz_exp, $raw_exp) = $tmp;
+        if ($downloadState == NULL) { 
+          echo  "<tr><td> $expType ($summit_exp) <td> loading imfiles <td> null <td bgcolor=\"yellow\"> <font color=\"red\">$count";
         } else {
-          if ($tmp[1] == 'run') { 
-            echo  "<tr><td>$tmp[0]<td> loading <td> null <td bgcolor=$columnHeaderColor> <font color=\"red\">$tmp[3]"; 
+          if ($downloadState == 'run') { 
+            echo  "<tr><td> $expType ($summit_exp) <td> summit_copy ($pz_exp) <td> saving ($pz_exp) <td bgcolor=$columnHeaderColor> <font color=\"red\">$count"; 
           } else {
-            if ($tmp[2] == NULL) { 
-              echo  "<tr><td>$tmp[0] <td> $tmp[1] <td> loading <td bgcolor=$columnHeaderColor> <font color=\"blue\">$tmp[3]";
+            if ($rawState == NULL) { 
+              echo  "<tr><td> $expType ($summit_exp) <td> $downloadState ($pz_exp) <td> registering <td bgcolor=$columnHeaderColor> <font color=\"blue\">$count";
             } else {
-              echo  "<tr><td>$tmp[0]<td> $tmp[1] <td> downloaded <td> $tmp[3]";
+              echo  "<tr><td> $expType ($summit_exp) <td> $downloadState ($pz_exp) <td> $rawState ($raw_exp) <td> $count";
             }
           }
         }
     }
-    // timer finished
+    //while ($qry->fetchInto($tmp)) {
+    //    list($expType, $downloadState, $rawState, $count) = $tmp;
+    //    if ($downloadState == NULL) { 
+    //      echo  "<tr><td> $expType <td> null <td> null <td bgcolor=\"yellow\"> <font color=\"red\">$count";
+    //    } else {
+    //      if ($downloadState == 'run') { 
+    //        echo  "<tr><td> $expType <td> loading <td> null <td bgcolor=$columnHeaderColor> <font color=\"red\">$count"; 
+    //      } else {
+    //        if ($rawState == NULL) { 
+    //          echo  "<tr><td> $expType <td> $downloadState <td> loading <td bgcolor=$columnHeaderColor> <font color=\"blue\">$count";
+    //        } else {
+    //          echo  "<tr><td> $expType <td> $downloadState <td> download ($rawState) <td> $count";
+    //        }
+    //      }
+    //    }
+    //}
+
     echo "<tr><th colspan=4>";
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $finish = $time;
-    $total_time = round(($finish - $start), 3);
-    echo "loading in $total_time seconds.";
-    $start= $finish;
+    // End timer
+    $total_time = round(microtime(true) - $start, 3);
+    echo "<center>loading in $total_time seconds<br></center>";
+
     echo "</th></tr>";
     echo "</table><br>";
+}
+
+function formatState($state) {
+    // Formats display of the state for better readability
+    if (is_null($state)) {
+        return "<span style='color: red;'>null</span>";
+    } elseif ($state == 'run') {
+        return "<span style='color: red;'>loading</span>";
+    } else {
+        return $state;
+    }
 }
 ###########################################################################
@@ -1608,5 +1645,5 @@
     echo "<script type=\"text/javascript\" src=\"loader.js\"></script>";
     echo "<br><div class=\"chartWithOverlay\" style=\"position: relative; width: 640px\">"; 
-    echo "  <div id=\"disk_div\" style=\"width:640px; height:1200px\"></div>";
+    echo "  <div id=\"disk_div\" style=\"width:640px; height:4000px\"></div>";
     echo "  <div class=\"overlay\" style=\"position: absolute; width: 100px; top: 35px; right: 20px;\">";
     echo "    <div style=\"font-size: 12px; height: 14px; border: 1px solid; background-color: #00ff00\"><center>Free</div>";
@@ -1686,7 +1723,8 @@
    echo "     },";
    echo "     bar: { groupWidth: '95%' },";
-   echo "     chartArea: {left:70, top:30, right:20, bottom:40},";
-   echo "     fontSize: 12,";
-   echo "     isStacked: true";
+   echo "     chartArea: {left:100, top:30, right:20, bottom:40},";
+   echo "     fontSize: 15,";
+   echo "     isStacked: true,";
+   echo "     colors: ['#76A7FA', '#FF5733', '#C70039', '#900C3F', '#581845']";
    echo "   };";
    echo "   var chart = new google.visualization.BarChart(document.getElementById('disk_div'));";
@@ -1821,14 +1859,18 @@
 
     $date = gmdate("Y-m-d");
-    $sql = "SELECT MAX(exp_id) FROM rawExp WHERE dateobs >= date_sub('$date', interval 20 day) AND dateobs <= date_sub('$date', interval 10 day)";
+    $sql = "SELECT MAX(exp_id) FROM rawExp WHERE dateobs BETWEEN DATE_SUB('$date', INTERVAL 20 DAY) AND DATE_SUB('$date', INTERVAL 10 DAY)";
+    if ($debug) {echo "$sql<br>";}
     $qry = $db->query($sql);
+
     if (dberror($qry)) {
-        print "*** WARNING: no data in period 10-20 days before requested date (query will be slower) **\n";
+        echo "*** WARNING: No data in the period 10-20 days before requested date (query will be slower) **\n";
         $refExpID = 0;
-    }
-    $qry->fetchInto($refExpID);
-    if ($refExpID[0] = 'NULL') {
-        $refExpID[0] = 0;
-    }
+    } else {
+        $qry->fetchInto($refExpID);
+        $refExpID = isset($refExpID[0]) ? $refExpID[0] : 0;
+    }
+    // Print the result of the query
+    if ($debug) {echo "The result of MAX(exp_id) is: $refExpID<br>";}
+    {echo "The result of MAX(exp_id) is: $refExpID<br>";}
 
     #Query for the needed data
@@ -1838,4 +1880,6 @@
 #    $sql.= " WHERE (rawExp.dateobs > utc_date() - INTERVAL 14 hour) and (rawExp.dateobs < utc_date() + INTERVAL 10 hour)";
     $sql.= " WHERE (rawExp.dateobs > utc_date())";
+#    $sql.= " WHERE (rawExp.dateobs > '2024-10-24')";
+#    $sql.= " AND (rawExp.dateobs < '2024-10-25')";
     $sql.= " AND exp_id > $refExpID[0]";
     $sql.= " AND exp_type = 'OBJECT' AND camRun.state like 'full' ORDER BY dateobs asc;";
@@ -1843,4 +1887,5 @@
     $qry = $db->query($sql);
     if (dberror($qry)) {echo "<b>error with $sql </b><br>\n";}
+#    echo "<b>error with $sql </b><br>\n";
     while ($qry->fetchInto($row)) {
         $DQarray[] = $row;
@@ -2044,10 +2089,10 @@
 
         #define new zeropoints
-        if(substr($row[5],0,1) == 'g') {$col_string = 'blue'; $zpt_off = $zp - 25.013;}
-        if(substr($row[5],0,1) == 'r') {$col_string = 'red'; $zpt_off = $zp - 24.840;}
-        if(substr($row[5],0,1) == 'i') {$col_string = '#6a3d9a'; $zpt_off = $zp - 24.711;}
-        if(substr($row[5],0,1) == 'z') {$col_string = 'green'; $zpt_off = $zp - 24.30;}
-        if(substr($row[5],0,1) == 'y') {$col_string = 'cyan'; $zpt_off = $zp - 23.57;}
-        if(substr($row[5],0,1) == 'w') {$col_string = 'grey'; $zpt_off = $zp - 26.000;}
+        if(substr($row[5],0,1) == 'g') {$col_string = '#00f000'; $zpt_off = $zp - 25.013;}
+        if(substr($row[5],0,1) == 'r') {$col_string = '#f00000'; $zpt_off = $zp - 24.840;}
+        if(substr($row[5],0,1) == 'i') {$col_string = '#f05000'; $zpt_off = $zp - 24.711;}
+        if(substr($row[5],0,1) == 'z') {$col_string = '#0050a0'; $zpt_off = $zp - 24.300;}
+        if(substr($row[5],0,1) == 'y') {$col_string = '#ffe000'; $zpt_off = $zp - 23.570;}
+        if(substr($row[5],0,1) == 'w') {$col_string = '#808080'; $zpt_off = $zp - 26.060;}
 
         $tt_string1 = sprintf('time: %s\n zeropoint: %s\n filter: %s\n exp_time: %s\n comment: %s', $timestamp, $zp,$row[5],$row[6],$row[7]);
@@ -2101,4 +2146,7 @@
 }
 
+
+
+
 ###########################################################################
 #
@@ -2108,8 +2156,5 @@
 function Gettimeseries($db, $selectedMode, $selectedLabel, $proj, $selectedStage) {
     // timer start
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $start = $time;
+    $start = microtime(true);
 
     // google chart javascript source code
@@ -2512,11 +2557,5 @@
  
     // timer end
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $finish = $time;
-    $total_time = round(($finish - $start), 3);
-    $start= $finish;
-    echo "<center>loading in $total_time seconds</center>";
+    echo "<center> loading in " . round((microtime(true) - $start), 3) . " seconds. </center>";
 }
 
@@ -2994,4 +3033,370 @@
 }
 
+
+###########################################################################
+#
+# Get data quality
+#
+###########################################################################
+function getDataQuality2($db) {
+    // Start timer
+    $start = microtime(true);
+
+    $mjdDay  = getMJD();
+    $expname = "o".$mjdDay."%";
+
+    $sql = "SELECT SUBTIME(dateobs, '10:00:00') AS time, 
+                   round(( 367*YEAR(dateobs)- FLOOR((7 * (YEAR(dateobs) + FLOOR((MONTH(dateobs) + 9) / 12))) / 4) + FLOOR(275 * MONTH(dateobs) / 9) 
+                   + DAY(dateobs) + 1721013.5 + (HOUR(dateobs) / 24.0) + (MINUTE(dateobs) / 1440.0) + (SECOND(dateobs) / 86400.0) - 2400000.5), 5) AS MJD, 
+                   filter, comment, ra*180/pi() as RA, decl*180/pi() as DECL, exp_name, alt, az, fwhm_major, fwhm_minor, zpt_obs, zpt_stdev, rawExp.exp_id 
+            FROM rawExp JOIN chipRun using (exp_id) JOIN camRun using (chip_id) JOIN camProcessedExp using (cam_id) 
+            WHERE rawExp.exp_name like '$expname'
+               AND exp_type = 'OBJECT' 
+               AND camRun.state like 'full' 
+               AND camProcessedExp.fault = 0 
+               AND camProcessedExp.zpt_obs != 0; ";
+
+    $DQarray = array();
+    $qry = $db->query($sql);
+    if (dberror($qry)) {
+        echo "<b>Error with $sql</b><br>\n";
+        return;
+    }
+    
+    while ($qry->fetchInto($row)) {
+        $DQarray[] = $row;
+    }
+    
+    // Ensure $DQarray is not empty
+    if (empty($DQarray)) {
+        echo "<center><b> No data for MJD: $mjdDay </b></center>";
+        return; // Stop execution if no data to encode
+    }
+    
+    // Convert data array to JSON for easier handling in JavaScript
+    $dataJson = json_encode($DQarray);
+    
+    if ($dataJson === false) {
+        echo "<b>Error encoding JSON:</b> " . json_last_error_msg(); // Display any JSON encoding errors
+        return; // Stop execution if JSON encoding fails
+    }
+    
+    echo "<script>console.log(" . json_encode($dataJson) . ");</script>"; // Log JSON output to console for debugging
+
+echo <<<HTML
+<script type="text/javascript" src="loader.js"></script>
+
+<script type="text/javascript">
+    google.charts.load('current', {packages: ['corechart']});
+
+    // Use the encoded JSON directly in JavaScript
+    const dataArray = JSON.parse('{$dataJson}'); // Directly parse the PHP JSON string
+
+    // draw FWHM vs MJD
+    function drawFWHMChart() {
+        var data = new google.visualization.DataTable();
+            data.addColumn('number', 'MJD');
+            data.addColumn('number', 'FWHM_major');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'FWHM_minor');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'seeing ~ 1"');
+            data.addColumn('number', 'seeing ~ 3"');
+
+        const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id] = row;
+
+            return [
+                parseFloat(mjd),      // Position Angle
+                parseFloat(iq_fwhm_maj),         // RA_offset (AST_R0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,
+                parseFloat(iq_fwhm_min),        // Dec_offset (AST_D0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,
+                4,
+                12
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'FWHM (MJD)',
+            titleTextStyle: {color: 'black', fontSize: 15},
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#0000ff', pointSize: 3, lineWidth: 1 },
+                1: { color: '#33a532', pointSize: 3, lineWidth: 1 },
+                2: { color: 'red', lineWidth: 2, pointSize: 0 },
+                3: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }
+            },
+            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: {count: -1}
+            },
+            vAxis: {
+                title: 'FWHM (pixels)',
+            },
+            tooltip: { isHtml: true }, // Render tooltips as HTML
+            chartArea: {left: '8%', top: 60, right: '5%', bottom: 50}, // Adjust left and right
+            fontSize: 12,
+        };
+
+        const chart = new google.visualization.LineChart(document.getElementById('dq_div_fwhm'));
+        chart.draw(data, options);
+    }
+
+    // draw zoomed zerpoint vs mjd
+    function drawZOOMZPTChart() {
+        var data = new google.visualization.DataTable();
+        data.addColumn('number', 'MJD');
+
+        // Add columns for each filter type to handle separate colors
+        data.addColumn('number', 'g (24.563, 25.013)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'r (24.750, 24.840)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'i (24.611, 24.711)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'z (24.240, 24.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'y (23.320, 23.570)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'w (26.000, 26.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+
+        const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id] = row;
+
+            // Initialize all filter values as null
+            let zp_g = null, zp_r = null, zp_i = null, zp_z = null, zp_y = null, zp_w = null;
+
+            // Set the zeropoint offset based on filter and assign it to the correct series
+            switch (filter[0]) {
+                case 'g':
+                    zp_g = zpt_obs - 24.563;
+                    break;
+                case 'r':
+                    zp_r = zpt_obs - 24.750;
+                    break;
+                case 'i':
+                    zp_i = zpt_obs - 24.611;
+                    break;
+                case 'z':
+                    zp_z = zpt_obs - 24.240;
+                    break;
+                case 'y':
+                   zp_y = zpt_obs - 23.320;
+                    break;
+                case 'w':
+                    zp_w = zpt_obs - 26.000;
+                    break;
+            }
+
+            return [
+                parseFloat(mjd), // MJD value
+                zp_g, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_g - zpt_stdev), parseFloat(zp_g - zpt_stdev*-1),
+                zp_r, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_r - zpt_stdev), parseFloat(zp_r - zpt_stdev*-1),
+                zp_i, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_i - zpt_stdev), parseFloat(zp_i - zpt_stdev*-1),
+                zp_z, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_z - zpt_stdev), parseFloat(zp_z - zpt_stdev*-1),
+                zp_y, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_y - zpt_stdev), parseFloat(zp_y - zpt_stdev*-1),
+                zp_w, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_w - zpt_stdev), parseFloat(zp_w - zpt_stdev*-1)
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'Zeropoint zoom-in (MJD)',
+            titleTextStyle: { color: 'black', fontSize: 15 },
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'start', maxLines: 3 },
+            series: {
+                0: { color: '#00f000', pointSize: 10, pointShape: 'circle',   linewidth: 1},  // 'g' filter
+                1: { color: '#f00000', pointSize: 10, pointShape: 'triangle', linewidth: 1},  // 'r' filter
+                2: { color: '#f05000', pointSize: 10, pointShape: 'square',   linewidth: 1},  // 'i' filter
+                3: { color: '#0050a0', pointSize: 10, pointShape: 'diamond',  linewidth: 1},  // 'z' filter
+                4: { color: '#ffe000', pointSize: 10, pointShape: 'star',     linewidth: 1},  // 'y' filter
+                5: { color: '#808080', pointSize: 10, pointShape: 'polygon',  linewidth: 1},  // 'w' filter
+            },
+            intervals: { color: 'red', lineWidth: 1, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: { count: -1 }
+            },
+            vAxis: {
+                title: 'Zeropoint (mag)',
+                viewWindow: {   min: -1.00, max: .5    },
+            },
+            tooltip: { isHtml: true },
+            chartArea: { left: '9%', top: 60, right: '5%', bottom: 50 },
+            fontSize: 12,
+        };
+
+        const chart = new google.visualization.LineChart(document.getElementById('dq_div_zoomzpt'));
+        chart.draw(data, options);
+    }
+
+    // draw zeropoint vs mjd
+    function drawZPTChart() {
+        var data = new google.visualization.DataTable();
+        data.addColumn('number', 'MJD');
+
+        // Add columns for each filter type to handle separate colors
+        data.addColumn('number', 'g' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'r' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'i' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'z' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'y' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'w' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+
+        // Count occurrences of each filter
+        const filterCounts = { g: 0, r: 0, i: 0, z: 0, y: 0, w: 0 };
+       const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id] = row;
+
+            // Initialize all filter values as null
+            let zp_g = null, zp_r = null, zp_i = null, zp_z = null, zp_y = null, zp_w = null;
+
+            // Increment the count for the filter
+            if (filterCounts.hasOwnProperty(filter[0])) {
+                filterCounts[filter[0]] += 1;
+            }
+
+            // Set the zeropoint offset based on filter and assign it to the correct series
+            switch (filter[0]) {
+                case 'g':
+                    zp_g = zpt_obs - 0.0;
+                    break;
+                case 'r':
+                    zp_r = zpt_obs - 0.0;
+                    break;
+                case 'i':
+                    zp_i = zpt_obs - 0.0;
+                    break;
+                case 'z':
+                    zp_z = zpt_obs - 0.0;
+                    break;
+                case 'y':
+                    zp_y = zpt_obs - 0.0;
+                    break;
+                case 'w':
+                    zp_w = zpt_obs - 0.0;
+                    break;
+            }
+
+            return [
+                parseFloat(mjd), // MJD value
+                zp_g, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_g - zpt_stdev), parseFloat(zp_g - zpt_stdev*-1),
+                zp_r, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_r - zpt_stdev), parseFloat(zp_r - zpt_stdev*-1),
+                zp_i, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_i - zpt_stdev), parseFloat(zp_i - zpt_stdev*-1),
+                zp_z, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_z - zpt_stdev), parseFloat(zp_z - zpt_stdev*-1),
+                zp_y, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_y - zpt_stdev), parseFloat(zp_y - zpt_stdev*-1),
+                zp_w, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_w - zpt_stdev), parseFloat(zp_w - zpt_stdev*-1),
+
+            ];
+        });
+      data.addRows(rows);
+
+        // Include counts in the title using string concatenation
+        const countsTitle = 'Zeropoint (MJD) g: ' + filterCounts.g + ', r: ' + filterCounts.r + ', i: ' + filterCounts.i + ', z: ' + filterCounts.z + ', y: ' + filterCounts.y + ', w: ' + filterCounts.w;
+
+
+        console.log(countsTitle);
+
+        const options = {
+            title: countsTitle,
+            titleTextStyle: { color: 'black', fontSize: 15 },
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#00f000', pointSize: 10, pointShape: 'circle',   linewidth: 1},  // 'g' filter
+                1: { color: '#f00000', pointSize: 10, pointShape: 'triangle', linewidth: 1},  // 'r' filter
+                2: { color: '#f05000', pointSize: 10, pointShape: 'square',   linewidth: 1},  // 'i' filter
+                3: { color: '#0050a0', pointSize: 10, pointShape: 'diamond',  linewidth: 1},  // 'z' filter
+                4: { color: '#ffe000', pointSize: 10, pointShape: 'star',     linewidth: 1},  // 'y' filter
+                5: { color: '#808080', pointSize: 10, pointShape: 'polygon',  linewidth: 1},  // 'w' filter
+            },
+            intervals: { color: 'red', lineWidth: 1, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: { count: -1 }
+            },
+            vAxis: {
+                title: 'Zeropoint (mag)'
+            },
+            tooltip: { isHtml: true },
+            chartArea: { left: '9%', top: 60, right: '5%', bottom: 50 },
+            fontSize: 12,
+        };
+
+        const chart = new google.visualization.LineChart(document.getElementById('dq_div_zpt'));
+        chart.draw(data, options);
+    }
+
+    google.charts.setOnLoadCallback(drawFWHMChart);
+    google.charts.setOnLoadCallback(drawZPTChart);
+    google.charts.setOnLoadCallback(drawZOOMZPTChart);
+
+</script>
+
+<div class="chartWithOverlay" style="position: relative; width: 640px; height:500px;">
+    <div id="dq_div_fwhm" style="width:640px;"></div>
+    <div class="overlay" style="position: absolute; width: 400px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 640px; height:500px;">
+    <div id="dq_div_zpt" style="width:640px;"></div>
+    <div class="overlay" style="position: absolute; width: 400px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 640px; height:500px;">
+    <div id="dq_div_zoomzpt" style="width:640px;"></div>
+    <div class="overlay" style="position: absolute; width: 400px; bottom: 60px; left: 85px;"></div>
+</div>
+
+HTML;
+    // End timer
+    $total_time = round(microtime(true) - $start, 3);
+    echo "<center>loading plot in $total_time seconds<br></center>";
+
+}
+
+
+
 function getprocrate ($proc1, $proc0, $trange) {
   if($proc1 > $proc0) {
Index: /branches/eam_branches/ipp-20230313/ippMonitor/raw/ipp.php
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/raw/ipp.php	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/raw/ipp.php	(revision 42751)
@@ -958,3 +958,29 @@
 }
 
+function getMJD() {
+    // Get the current date and time in UTC as a Unix timestamp
+    $currentTimestamp = time();
+    
+    // Convert the Unix timestamp to Julian Date (JD)
+    $jd = 2440587.5 + ($currentTimestamp / 86400);
+    
+    // Calculate the Modified Julian Date (MJD)
+    $mjd = $jd - 2400000.5;
+    $mjdDay = floor($mjd); // Get only the day part of MJD
+    
+    // Concatenate the desired string for expname
+    //$expname = "o" . $mjdDay . "%";
+    
+    // Format the current date in 'YYYY-MM-DD-HH:mm:ss' for display
+    //$currentUTC = gmdate('Y-m-d-H:i:s', $currentTimestamp);
+    
+    // Display the result
+    //echo "Current UTC: $currentUTC, MJD: $mjdDay, expname: $expname<br>";
+    
+    // Return MJD day as an integer
+    return $mjdDay;
+}
+
+
+
 ?>
Index: /branches/eam_branches/ipp-20230313/ippMonitor/raw/ipp.plots.dat
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/raw/ipp.plots.dat	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/raw/ipp.plots.dat	(revision 42751)
@@ -22,2 +22,7 @@
 menulink  | menuselect      | link    | Plot Background (chipProcessedImfile) vs Moon Phase (rawExp) | scatterCpiBgReMpImage.php
 menulink  | menuselect      | link    | Plot Background (chipProcessedImfile) vs Sun Angle (rawExp) | scatterCpiBgReSaImage.php
+
+menutop   | menutop      | plain   | &nbsp;                                 | 
+menulink  | menuselect      | link    | pointing status | scatterPlotPointing.php
+menulink  | menuselect      | link    | data quality status | scatterPlotDataQuality.php
+menulink  | menuselect      | link    | airmass status | scatterPlotAirmassMcal.php
Index: /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotAirmassMcal.php
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotAirmassMcal.php	(revision 42751)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotAirmassMcal.php	(revision 42751)
@@ -0,0 +1,633 @@
+<?php 
+
+include 'ipp.php';
+delete_old_tmp_files();
+
+$ID = checkID ();
+
+// require an explicit project
+if (! $ID['proj']) { projectform ($ID); }
+
+$db = dbconnect($ID['proj']);
+
+if ($ID['menu']) {
+  $myMenu = $ID['menu'];
+} else {
+  $myMenu = "ipp.plots.dat";
+}
+
+menu($myMenu, 'Data Quality', 'ipp.css', $ID['link'], $ID['proj']);
+
+echo "<p> Data Quality </p>";
+
+// set up the form
+echo "<form action=\"scatterPlotAirmassMcal.php\" method=\"POST\">\n";
+
+$restricted = 0;
+
+// define restrictiosn to the queries
+// ** TABLE RESTRICTIONS **
+$WHERE = "WHERE camRun.state = 'full' AND chipRun.exp_id = rawExp.exp_id AND camRun.chip_id = chipRun.chip_id AND camProcessedExp.cam_id = camRun.cam_id AND camProcessedExp.fault = 0 AND camProcessedExp.zpt_obs != 0";
+$WHERE = check_restrict ('rawExp.exp_name', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.telescope', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.camera', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('camRun.label', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.ra', $WHERE, 'min', 0.017453);
+$WHERE = check_restrict ('rawExp.ra', $WHERE, 'max', 0.017453);
+$WHERE = check_restrict ('rawExp.decl', $WHERE, 'min', 0.017453);
+$WHERE = check_restrict ('rawExp.decl', $WHERE, 'max', 0.017453);
+$WHERE = check_restrict ('rawExp.comment', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.object', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.filter', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'max', 1.0);
+
+if ($restricted == 0) {//Don't select anything
+  if ($WHERE == "") {
+    $WHERE = "WHERE (0 > 1)";
+  } else {
+    $WHERE = "WHERE (0 > 1)";
+  }
+}
+
+// get the result table count
+$sql = "SELECT count(*) FROM camRun, chipRun, rawExp, camProcessedExp $WHERE";
+
+$qry = $db->query($sql);
+if (dberror($qry)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table count</b><br>\n";
+  echo "<br><small><b> count query : $sql </b></small><br>\n";
+  menu_end();
+}
+if (!dbFetchInto($qry, $row)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table count</b><br>\n";
+  echo "<br><small><b> count query : $sql </b></small><br>\n";
+  menu_end();
+}
+$nValues = $row[0];
+
+// group number of filters
+$sql = "SELECT count(*), filter FROM camRun, chipRun, rawExp, camProcessedExp $WHERE group by filter";
+$filterCounts = array('g' => 0, 'r' => 0, 'i' => 0, 'z' => 0, 'y' => 0, 'w' => 0);
+
+// Accumulate counts by filter
+$qry = $db->query($sql);
+while ($qry->fetchInto($dat)) {
+    $filter = strtolower(substr($dat[1], 0, 1)); // Get the first letter of the filter
+    $filterCounts[$filter] += $dat[0];
+}
+
+// maximum number of query items
+$qmax   = 10000;
+
+// Display message based on count
+if ($nValues > $qmax) {
+  echo "<b>$nValues match selection, but only showing $qmax exposures randomly</b><br>\n";
+} else {
+  echo "<b>$nValues match selection</b><br>\n";
+}
+
+// Display filter counts
+echo "<b>Filter counts: g: {$filterCounts['g']}, r: {$filterCounts['r']}, i: {$filterCounts['i']}, z: {$filterCounts['z']}, y: {$filterCounts['y']}, w: {$filterCounts['w']}</b><br>";
+
+// Call the function and display the result, function in ipp.php
+$mjdday = getMJD();
+echo "<b>MJD today: $mjdday</b><br><br>";
+
+// Modify the second query to limit to $qmax if $nValues is larger than $qmax
+$limitClause = ($nValues > $qmax) ? "ORDER BY RAND() LIMIT $qmax" : "";
+
+$sql = "SELECT SUBTIME(dateobs, '10:00:00') AS time, round(( 367*YEAR(dateobs)- FLOOR((7 * (YEAR(dateobs) + FLOOR((MONTH(dateobs) + 9) / 12))) / 4) + FLOOR(275 * MONTH(dateobs) / 9) + DAY(dateobs) + 1721013.5 + (HOUR(dateobs) / 24.0) + (MINUTE(dateobs) / 1440.0) + (SECOND(dateobs) / 86400.0) - 2400000.5), 5) AS MJD, filter, comment, ra*180/pi() as RA, decl*180/pi() as DECL, exp_name, alt, az, iq_fwhm_major, iq_fwhm_minor, zpt_obs, zpt_stdev, rawExp.exp_id, airmass FROM camRun, chipRun, rawExp, camProcessedExp $WHERE $limitClause";
+$qry = $db->query($sql);
+
+if (dberror($qry)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table</b><br>\n";
+  echo "<br><small><b> table query : $sql </b></small><br>\n";
+  menu_end();
+}
+
+// ** HEAD CODE **
+
+// ** BUTTON RESTRICTIONS **
+$buttonLink = button_restrict_string ('rawExp.exp_name', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.telescope', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.camera', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_string ('camRun.label', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.comment', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.object', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.filter', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.bg_stdev', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.bg_stdev', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.bg_stdev', $buttonLink);
+navigate_buttons ($rowStart, $rowLast, $dTABLE, $rowTotal, $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+
+echo "&nbsp; : &nbsp; or enter start row: <input type=\"text\" name=\"from\" size=\"5\" value=\"$rowStart\">\n";
+
+// set up the table
+echo "<table class=list>\n";
+
+// echo "<tr><td></td>\n"; // first field is a label set below for the query rows only
+// ** TABLE HEADER **
+echo "<tr><td></td>\n";
+write_header_cell ("list", "Exp Name");
+write_header_cell ("list", "Exp ID");
+write_header_cell ("list", "Telescope");
+write_header_cell ("list", "Camera");
+write_header_cell ("list", "Date/Time");
+write_header_cell ("list", "Label");
+write_header_cell ("list", "RA");
+write_header_cell ("list", "DEC");
+write_header_cell ("list", "Comment");
+write_header_cell ("list", "Object");
+write_header_cell ("list", "FILTER");
+write_header_cell ("list", "exp_time");
+write_header_cell ("list", "airmass");
+write_header_cell ("list", "backgnd");
+write_header_cell ("list", "stdev");
+echo "</tr>\n";
+echo "<tr><td></td>\n";
+write_sort_cell ("list", "rawExp.exp_name", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.exp_id", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.telescope", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.camera", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.dateobs", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "camRun.label", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.ra", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.decl", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.comment", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.object", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.filter", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.exp_time", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.airmass", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.bg", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+write_sort_cell ("list", "rawExp.bg_stdev", $buttonLink, $ID, 'scatterPlotAirmassMcal.php');
+echo "</tr>\n";
+// echo "</tr>\n";
+
+// query restriction form
+// echo "<tr>\n";
+// echo "<td class=list> <input type=\"text\" name=\"expID\"></td>\n";
+// ** TABLE QUERY **
+echo "<tr><td>&ge;</td>\n";
+write_query_row ('rawExp.exp_name', 5, 'string');
+write_query_row ('rawExp.exp_id', 5, 'min');
+write_query_row ('rawExp.telescope', 10, 'string');
+write_query_row ('rawExp.camera', 10, 'string');
+write_query_row ('rawExp.dateobs', 19, 'min');
+write_query_row ('camRun.label', 10, 'string');
+write_query_row ('rawExp.ra', 8, 'min');
+write_query_row ('rawExp.decl', 8, 'min');
+write_query_row ('rawExp.comment', 65, 'string');
+write_query_row ('rawExp.object', 8, 'string');
+write_query_row ('rawExp.filter', 10, 'string');
+write_query_row ('rawExp.exp_time', 5, 'min');
+write_query_row ('rawExp.airmass', 5, 'min');
+write_query_row ('rawExp.bg', 5, 'min');
+write_query_row ('rawExp.bg_stdev', 5, 'min');
+echo "</tr><tr><td>&le;</td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.exp_id', 5, 'max');
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.dateobs', 19, 'max');
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.ra', 8, 'max');
+write_query_row ('rawExp.decl', 8, 'max');
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.exp_time', 5, 'max');
+write_query_row ('rawExp.airmass', 5, 'max');
+write_query_row ('rawExp.bg', 5, 'max');
+write_query_row ('rawExp.bg_stdev', 5, 'max');
+echo "</tr>\n";
+// echo "</tr>\n";
+
+// query restriction form
+// echo "<tr>\n";
+// echo "<td class=list> <input type=\"text\" name=\"expID\"></td>\n";
+// TABLE QUERY 
+// echo "</tr>\n";
+
+// close the table and form
+echo "</table>\n";
+echo "<input type=\"submit\" name=\"constraints\" value=\"refine search\">\n";
+$pass = $ID['pass'];
+$proj = $ID['proj'];
+$menu = $ID['menu'];
+echo "<input type=\"hidden\" name=\"pass\" value=\"$pass\">\n";
+echo "<input type=\"hidden\" name=\"proj\" value=\"$proj\">\n";
+echo "<input type=\"hidden\" name=\"menu\" value=\"$menu\">\n";
+echo "</form>\n";
+
+if ($row[0] == 0) {
+  menu_end();
+}
+
+//$datFilename = tempnam("/tmp", "dvodat.");
+//$pngFilename = $datFilename.".png";
+//
+//$datfile = fopen($datFilename, "w");
+//chmod($datFilename, 0777);
+//
+//// output the results to tmpfile
+//while (dbFetchInto($qry, $row)) {
+//  $line = "";
+//  foreach ($row as $i => $value) {
+//    switch ($value) {
+//    case 'g.00002':
+//      $filter = 1;
+//      break;
+//    case 'r.00002':
+//      $filter = 2;
+//      break;
+//    case 'i.00002':
+//      $filter = 3;
+//      break;
+//    case 'z.00002':
+//      $filter = 4;
+//      break;
+//    case 'y.00002':
+//      $filter = 5;
+//      break;
+//    case 'w.00002':
+//      $filter = 6;
+//      break;
+//    case 'g.00000':
+//      $filter = 1;
+//      break;
+//    case 'r.00000':
+//      $filter = 2;
+//      break;
+//    case 'i.00000':
+//      $filter = 3;
+//      break;
+//    case 'z.00000':
+//      $filter = 4;
+//      break;
+//    case 'y.00000':
+//      $filter = 5;
+//      break;
+//    case 'w.00000':
+//      $filter = 6;
+//      break;
+//    case 'OPEN':
+//      $filter = 0;
+//      break;
+//    case 'g':
+//      $filter = 1;
+//      break;
+//    case 'r':
+//      $filter = 2;
+//      break;
+//    case 'i':
+//      $filter = 3;
+//      break;
+//    case 'z':
+//      $filter = 4;
+//      break;
+//    case 'y':
+//      $filter = 5;
+//      break;
+//    case 'w':
+//      $filter = 6;
+//      break;
+//    default:
+//      $filter = $value;
+//      break;
+//    }
+//    $line .= "$filter ";
+//  }
+//  if (preg_match('/^[ \t]*$/', $line) == 0) {//Don't write empty lines
+//    $line = preg_replace('/[ \t]*$/', '', $line);
+//    fwrite ($datfile, $line."\n");
+//  }
+//}
+//fclose($datfile);
+//
+//echo "<img src=\"skyplot.php?input=$datFilename&output=$pngFilename&title='Sky_Plot_Raw'\"><br>\n";
+//
+// ** TAIL CODE **
+
+echo "<small> WHERE: $WHERE<br><br></small>\n";
+echo "<small> SQL: $sql<br><br></small>\n";
+
+//echo "Temporary files are [$datFilename] and [$pngFilename]\n";
+
+echo "<br><a href=\"https://panstarrs.atlassian.net/browse/IPP-2244\" target=new><font color = \"blue\">IPP-2244</font></a><br>";
+
+// Start timer
+$start = microtime(true);
+
+$DQarray = array();
+$qry = $db->query($sql);
+if (dberror($qry)) {
+    echo "<b>Error with $sql</b><br>\n";
+    return;
+}
+
+while ($qry->fetchInto($row)) {
+    $DQarray[] = $row;
+}
+
+// Ensure $DQarray is not empty
+if (empty($DQarray)) {
+    echo "<b>Error:</b> Data array is empty.";
+    return; // Stop execution if no data to encode
+}
+
+// Convert data array to JSON for easier handling in JavaScript
+$dataJson = json_encode($DQarray);
+
+if ($dataJson === false) {
+    echo "<b>Error encoding JSON:</b> " . json_last_error_msg(); // Display any JSON encoding errors
+    return; // Stop execution if JSON encoding fails
+}
+
+echo "<script>console.log(" . json_encode($dataJson) . ");</script>"; // Log JSON output to console for debugging
+
+echo <<<HTML
+<!-- Attempt to load Google Charts library from the Google CDN -->
+<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js" onerror="loadLocalGoogleCharts()"></script>
+
+<script type="text/javascript">
+    // Check if Google Charts library loaded successfully
+    window.addEventListener("load", function() {
+        if (typeof google === "undefined" || typeof google.charts === "undefined") {
+            loadLocalGoogleCharts();
+        }
+    });
+
+    // Function to load local version of Google Charts if CDN fails
+    function loadLocalGoogleCharts() {
+        console.warn("Google Charts CDN failed, loading local loader.js instead.");
+        var script = document.createElement("script");
+        script.src = "loader.js"; // Path to your local loader.js file
+        document.head.appendChild(script);
+    }
+</script>
+
+<script type="text/javascript">
+    google.charts.load('current', {packages: ['corechart']});
+
+    // Use the encoded JSON directly in JavaScript
+    const dataArray = JSON.parse('{$dataJson}'); // Directly parse the PHP JSON string
+
+    // draw Airmass vs MJD
+    function drawAIRMASSChart() {
+        var data = new google.visualization.DataTable();
+        data.addColumn('number', 'MJD');
+    
+        // Add columns for each filter type to handle separate colors
+        data.addColumn('number', 'g (24.563, 25.013)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn('number', 'r (24.750, 24.840)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn('number', 'i (24.611, 24.711)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn('number', 'z (24.240, 24.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn('number', 'y (23.320, 23.570)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn('number', 'w (26.000, 26.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+    
+        const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id, airmass] = row;
+    
+            // Initialize all filter values as null
+            let am_g = null, am_r = null, am_i = null, am_z = null, am_y = null, am_w = null;
+    
+            // Set the zeropoint offset based on filter and assign it to the correct series
+            switch (filter[0]) {
+                case 'g':
+                    am_g = airmass;
+                    break;
+                case 'r':
+                    am_r = airmass;
+                    break;
+                case 'i':
+                    am_i = airmass;
+                    break;
+                case 'z':
+                    am_z = airmass;
+                    break;
+                case 'y':
+                    am_y = airmass;
+                    break;
+                case 'w':
+                    am_w = airmass;
+                    break;
+            }
+    
+            return [
+                parseFloat(mjd), // MJD value
+                parseFloat(am_g), "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  
+                parseFloat(am_r), "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  
+                parseFloat(am_i), "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  
+                parseFloat(am_z), "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  
+                parseFloat(am_y), "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  
+                parseFloat(am_w), "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  
+    
+            ];
+        });
+    
+        data.addRows(rows);
+    
+        const options = {
+            title: 'Airmass (MJD)',
+            titleTextStyle: { color: 'black', fontSize: 15 },
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#00f000', pointSize: 5, pointShape: 'circle',   dataOpacity: .6},  // 'g' filter
+                1: { color: '#f00000', pointSize: 5, pointShape: 'triangle', dataOpacity: .6},  // 'r' filter
+                2: { color: '#f05000', pointSize: 5, pointShape: 'square',   dataOpacity: .6},  // 'i' filter
+                3: { color: '#0050a0', pointSize: 5, pointShape: 'diamond',  dataOpacity: .6},  // 'z' filter
+                4: { color: '#ffe000', pointSize: 5, pointShape: 'star',     dataOpacity: .6},  // 'y' filter
+                5: { color: '#808080', pointSize: 5, pointShape: 'polygon',  dataOpacity: .6},  // 'w' filter
+            },
+            hAxis: {
+                title: 'MJD',
+                gridlines: { count: -1 }
+            },
+            vAxis: {
+                title: 'Airmass',
+            },
+            tooltip: { isHtml: true },
+            chartArea: { left: '7%', top: 60, right: '4%', bottom: 50 },
+            fontSize: 15,
+        };
+    
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_airmass'));
+        chart.draw(data, options);
+    }
+
+    // draw zoomed zerpoint vs mjd
+    function drawZOOMZPTChart() {
+        var data = new google.visualization.DataTable();
+        data.addColumn('number', 'MJD');
+    
+        // Add columns for each filter type to handle separate colors
+        data.addColumn('number', 'g (24.563, 25.013)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'r (24.750, 24.840)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'i (24.611, 24.711)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'z (24.240, 24.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'y (23.320, 23.570)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'w (26.000, 26.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+    
+        const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id, airmass] = row;
+    
+            // Initialize all filter values as null
+            let zp_g = null, zp_r = null, zp_i = null, zp_z = null, zp_y = null, zp_w = null;
+    
+            // Set the zeropoint offset based on filter and assign it to the correct series
+            switch (filter[0]) {
+                case 'g':
+                    zp_g = 24.563 - zpt_obs;
+                    break;
+                case 'r':
+                    zp_r = 24.750 - zpt_obs;
+                    break;
+                case 'i':
+                    zp_i = 24.611 - zpt_obs;
+                    break;
+                case 'z':
+                    zp_z = 24.240 - zpt_obs;
+                    break;
+                case 'y':
+                    zp_y = 23.320 - zpt_obs;
+                    break;
+                case 'w':
+                    zp_w = 26.060 - zpt_obs;
+                    break;
+            }
+    
+            return [
+                parseFloat(airmass), // MJD value
+                zp_g, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>zpt_obs: "+zpt_obs, parseFloat(zp_g - zpt_stdev), parseFloat(zp_g - zpt_stdev*-1),
+                zp_r, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>zpt_obs: "+zpt_obs, parseFloat(zp_r - zpt_stdev), parseFloat(zp_r - zpt_stdev*-1),
+                zp_i, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>zpt_obs: "+zpt_obs, parseFloat(zp_i - zpt_stdev), parseFloat(zp_i - zpt_stdev*-1),
+                zp_z, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>zpt_obs: "+zpt_obs, parseFloat(zp_z - zpt_stdev), parseFloat(zp_z - zpt_stdev*-1),
+                zp_y, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>zpt_obs: "+zpt_obs, parseFloat(zp_y - zpt_stdev), parseFloat(zp_y - zpt_stdev*-1),
+                zp_w, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>zpt_obs: "+zpt_obs, parseFloat(zp_w - zpt_stdev), parseFloat(zp_w - zpt_stdev*-1),
+    
+            ];
+        });
+    
+        data.addRows(rows);
+    
+        const options = {
+            title: 'Mcal (Airmass)',
+            titleTextStyle: { color: 'black', fontSize: 15 },
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#00f000', pointSize: 5, pointShape: 'circle',   dataOpacity: .6},  // 'g' filter
+                1: { color: '#f00000', pointSize: 5, pointShape: 'triangle', dataOpacity: .6},  // 'r' filter
+                2: { color: '#f05000', pointSize: 5, pointShape: 'square',   dataOpacity: .6},  // 'i' filter
+                3: { color: '#0050a0', pointSize: 5, pointShape: 'diamond',  dataOpacity: .6},  // 'z' filter
+                4: { color: '#ffe000', pointSize: 5, pointShape: 'star',     dataOpacity: .6},  // 'y' filter
+                5: { color: '#808080', pointSize: 5, pointShape: 'polygon',  dataOpacity: .6},  // 'w' filter
+            },
+            intervals: { color: 'red', lineWidth: .2, style: 'sticks' },
+            hAxis: {
+                title: 'Airmass',
+                gridlines: { count: -1 },
+                //viewWindow: { min: 0.85, max: 3.00    },
+            },
+            vAxis: {
+                title: 'obs_zp - ref_zp',
+                //viewWindow: { min: -1.2, max: 1.20    },
+
+            },
+            tooltip: { isHtml: true },
+            chartArea: { left: '7%', top: 60, right: '4%', bottom: 50 },
+            fontSize: 15,
+        };
+    
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_zoomzpt'));
+        chart.draw(data, options);
+    }
+
+    google.charts.setOnLoadCallback(drawAIRMASSChart);
+    google.charts.setOnLoadCallback(drawZOOMZPTChart);
+</script>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_airmass" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_zoomzpt" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+HTML;
+
+// End timer
+$total_time = round(microtime(true) - $start, 3);
+echo "<center>Loading plot in $total_time seconds<br></center>";
+
+menu_end();
+
+?>
Index: /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotDataQuality.php
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotDataQuality.php	(revision 42751)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotDataQuality.php	(revision 42751)
@@ -0,0 +1,720 @@
+<?php 
+
+include 'ipp.php';
+delete_old_tmp_files();
+
+$ID = checkID ();
+
+// require an explicit project
+if (! $ID['proj']) { projectform ($ID); }
+
+$db = dbconnect($ID['proj']);
+
+if ($ID['menu']) {
+  $myMenu = $ID['menu'];
+} else {
+  $myMenu = "ipp.plots.dat";
+}
+
+menu($myMenu, 'Data Quality', 'ipp.css', $ID['link'], $ID['proj']);
+
+echo "<p> Data Quality </p>";
+
+// set up the form
+echo "<form action=\"scatterPlotDataQuality.php\" method=\"POST\">\n";
+
+$restricted = 0;
+
+// define restrictiosn to the queries
+// ** TABLE RESTRICTIONS **
+$WHERE = "WHERE camRun.state = 'full' AND chipRun.exp_id = rawExp.exp_id AND camRun.chip_id = chipRun.chip_id AND camProcessedExp.cam_id = camRun.cam_id AND camProcessedExp.fault = 0 AND camProcessedExp.zpt_obs != 0";
+$WHERE = check_restrict ('rawExp.exp_name', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.telescope', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.camera', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('camRun.label', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.ra', $WHERE, 'min', 0.017453);
+$WHERE = check_restrict ('rawExp.ra', $WHERE, 'max', 0.017453);
+$WHERE = check_restrict ('rawExp.decl', $WHERE, 'min', 0.017453);
+$WHERE = check_restrict ('rawExp.decl', $WHERE, 'max', 0.017453);
+$WHERE = check_restrict ('rawExp.comment', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.object', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.filter', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'max', 1.0);
+
+if ($restricted == 0) {//Don't select anything
+  if ($WHERE == "") {
+    $WHERE = "WHERE (0 > 1)";
+  } else {
+    $WHERE = "WHERE (0 > 1)";
+  }
+}
+
+// get the result table count
+$sql = "SELECT count(*) FROM camRun, chipRun, rawExp, camProcessedExp $WHERE";
+
+$qry = $db->query($sql);
+if (dberror($qry)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table count</b><br>\n";
+  echo "<br><small><b> count query : $sql </b></small><br>\n";
+  menu_end();
+}
+if (!dbFetchInto($qry, $row)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table count</b><br>\n";
+  echo "<br><small><b> count query : $sql </b></small><br>\n";
+  menu_end();
+}
+$nValues = $row[0];
+
+// group number of filters
+$sql = "SELECT count(*), filter FROM camRun, chipRun, rawExp, camProcessedExp $WHERE group by filter";
+$filterCounts = array('g' => 0, 'r' => 0, 'i' => 0, 'z' => 0, 'y' => 0, 'w' => 0);
+
+// Accumulate counts by filter
+$qry = $db->query($sql);
+while ($qry->fetchInto($dat)) {
+    $filter = strtolower(substr($dat[1], 0, 1)); // Get the first letter of the filter
+    $filterCounts[$filter] += $dat[0];
+}
+
+// maximum number of query items
+$qmax   = 10000;
+
+// Display message based on count
+if ($nValues > $qmax) {
+  echo "<b>$nValues match selection, but only showing $qmax exposures randomly</b><br>\n";
+} else {
+  echo "<b>$nValues match selection</b><br>\n";
+}
+
+// Display filter counts
+echo "<b>Filter counts: g: {$filterCounts['g']}, r: {$filterCounts['r']}, i: {$filterCounts['i']}, z: {$filterCounts['z']}, y: {$filterCounts['y']}, w: {$filterCounts['w']}</b><br>";
+
+// Call the function and display the result, function in ipp.php
+$mjdday = getMJD();
+echo "<b>MJD today: $mjdday</b><br><br>";
+
+// Modify the second query to limit to $qmax if $nValues is larger than $qmax
+$limitClause = ($nValues > $qmax) ? "ORDER BY RAND() LIMIT $qmax" : "";
+
+$sql = "SELECT SUBTIME(dateobs, '10:00:00') AS time, round(( 367*YEAR(dateobs)- FLOOR((7 * (YEAR(dateobs) + FLOOR((MONTH(dateobs) + 9) / 12))) / 4) + FLOOR(275 * MONTH(dateobs) / 9) + DAY(dateobs) + 1721013.5 + (HOUR(dateobs) / 24.0) + (MINUTE(dateobs) / 1440.0) + (SECOND(dateobs) / 86400.0) - 2400000.5), 5) AS MJD, filter, comment, ra*180/pi() as RA, decl*180/pi() as DECL, exp_name, alt, az, iq_fwhm_major, iq_fwhm_minor, zpt_obs, zpt_stdev, rawExp.exp_id FROM camRun, chipRun, rawExp, camProcessedExp $WHERE $limitClause";
+$qry = $db->query($sql);
+
+if (dberror($qry)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table</b><br>\n";
+  echo "<br><small><b> table query : $sql </b></small><br>\n";
+  menu_end();
+}
+
+// ** HEAD CODE **
+
+// ** BUTTON RESTRICTIONS **
+$buttonLink = button_restrict_string ('rawExp.exp_name', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.telescope', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.camera', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_string ('camRun.label', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.comment', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.object', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.filter', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.bg_stdev', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.bg_stdev', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.bg_stdev', $buttonLink);
+navigate_buttons ($rowStart, $rowLast, $dTABLE, $rowTotal, $buttonLink, $ID, 'scatterPlotDataQuality.php');
+
+echo "&nbsp; : &nbsp; or enter start row: <input type=\"text\" name=\"from\" size=\"5\" value=\"$rowStart\">\n";
+
+// set up the table
+echo "<table class=list>\n";
+
+// echo "<tr><td></td>\n"; // first field is a label set below for the query rows only
+// ** TABLE HEADER **
+echo "<tr><td></td>\n";
+write_header_cell ("list", "Exp Name");
+write_header_cell ("list", "Exp ID");
+write_header_cell ("list", "Telescope");
+write_header_cell ("list", "Camera");
+write_header_cell ("list", "Date/Time");
+write_header_cell ("list", "Label");
+write_header_cell ("list", "RA");
+write_header_cell ("list", "DEC");
+write_header_cell ("list", "Comment");
+write_header_cell ("list", "Object");
+write_header_cell ("list", "FILTER");
+write_header_cell ("list", "exp_time");
+write_header_cell ("list", "airmass");
+write_header_cell ("list", "backgnd");
+write_header_cell ("list", "stdev");
+echo "</tr>\n";
+echo "<tr><td></td>\n";
+write_sort_cell ("list", "rawExp.exp_name", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.exp_id", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.telescope", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.camera", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.dateobs", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "camRun.label", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.ra", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.decl", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.comment", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.object", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.filter", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.exp_time", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.airmass", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.bg", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+write_sort_cell ("list", "rawExp.bg_stdev", $buttonLink, $ID, 'scatterPlotDataQuality.php');
+echo "</tr>\n";
+// echo "</tr>\n";
+
+// query restriction form
+// echo "<tr>\n";
+// echo "<td class=list> <input type=\"text\" name=\"expID\"></td>\n";
+// ** TABLE QUERY **
+echo "<tr><td>&ge;</td>\n";
+write_query_row ('rawExp.exp_name', 5, 'string');
+write_query_row ('rawExp.exp_id', 5, 'min');
+write_query_row ('rawExp.telescope', 10, 'string');
+write_query_row ('rawExp.camera', 10, 'string');
+write_query_row ('rawExp.dateobs', 19, 'min');
+write_query_row ('camRun.label', 10, 'string');
+write_query_row ('rawExp.ra', 8, 'min');
+write_query_row ('rawExp.decl', 8, 'min');
+write_query_row ('rawExp.comment', 65, 'string');
+write_query_row ('rawExp.object', 8, 'string');
+write_query_row ('rawExp.filter', 10, 'string');
+write_query_row ('rawExp.exp_time', 5, 'min');
+write_query_row ('rawExp.airmass', 5, 'min');
+write_query_row ('rawExp.bg', 5, 'min');
+write_query_row ('rawExp.bg_stdev', 5, 'min');
+echo "</tr><tr><td>&le;</td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.exp_id', 5, 'max');
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.dateobs', 19, 'max');
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.ra', 8, 'max');
+write_query_row ('rawExp.decl', 8, 'max');
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.exp_time', 5, 'max');
+write_query_row ('rawExp.airmass', 5, 'max');
+write_query_row ('rawExp.bg', 5, 'max');
+write_query_row ('rawExp.bg_stdev', 5, 'max');
+echo "</tr>\n";
+// echo "</tr>\n";
+
+// query restriction form
+// echo "<tr>\n";
+// echo "<td class=list> <input type=\"text\" name=\"expID\"></td>\n";
+// TABLE QUERY 
+// echo "</tr>\n";
+
+// close the table and form
+echo "</table>\n";
+echo "<input type=\"submit\" name=\"constraints\" value=\"refine search\">\n";
+$pass = $ID['pass'];
+$proj = $ID['proj'];
+$menu = $ID['menu'];
+echo "<input type=\"hidden\" name=\"pass\" value=\"$pass\">\n";
+echo "<input type=\"hidden\" name=\"proj\" value=\"$proj\">\n";
+echo "<input type=\"hidden\" name=\"menu\" value=\"$menu\">\n";
+echo "</form>\n";
+
+if ($row[0] == 0) {
+  menu_end();
+}
+
+//$datFilename = tempnam("/tmp", "dvodat.");
+//$pngFilename = $datFilename.".png";
+//
+//$datfile = fopen($datFilename, "w");
+//chmod($datFilename, 0777);
+//
+//// output the results to tmpfile
+//while (dbFetchInto($qry, $row)) {
+//  $line = "";
+//  foreach ($row as $i => $value) {
+//    switch ($value) {
+//    case 'g.00002':
+//      $filter = 1;
+//      break;
+//    case 'r.00002':
+//      $filter = 2;
+//      break;
+//    case 'i.00002':
+//      $filter = 3;
+//      break;
+//    case 'z.00002':
+//      $filter = 4;
+//      break;
+//    case 'y.00002':
+//      $filter = 5;
+//      break;
+//    case 'w.00002':
+//      $filter = 6;
+//      break;
+//    case 'g.00000':
+//      $filter = 1;
+//      break;
+//    case 'r.00000':
+//      $filter = 2;
+//      break;
+//    case 'i.00000':
+//      $filter = 3;
+//      break;
+//    case 'z.00000':
+//      $filter = 4;
+//      break;
+//    case 'y.00000':
+//      $filter = 5;
+//      break;
+//    case 'w.00000':
+//      $filter = 6;
+//      break;
+//    case 'OPEN':
+//      $filter = 0;
+//      break;
+//    case 'g':
+//      $filter = 1;
+//      break;
+//    case 'r':
+//      $filter = 2;
+//      break;
+//    case 'i':
+//      $filter = 3;
+//      break;
+//    case 'z':
+//      $filter = 4;
+//      break;
+//    case 'y':
+//      $filter = 5;
+//      break;
+//    case 'w':
+//      $filter = 6;
+//      break;
+//    default:
+//      $filter = $value;
+//      break;
+//    }
+//    $line .= "$filter ";
+//  }
+//  if (preg_match('/^[ \t]*$/', $line) == 0) {//Don't write empty lines
+//    $line = preg_replace('/[ \t]*$/', '', $line);
+//    fwrite ($datfile, $line."\n");
+//  }
+//}
+//fclose($datfile);
+//
+//echo "<img src=\"skyplot.php?input=$datFilename&output=$pngFilename&title='Sky_Plot_Raw'\"><br>\n";
+//
+// ** TAIL CODE **
+
+echo "<small> WHERE: $WHERE<br><br></small>\n";
+echo "<small> SQL: $sql<br><br></small>\n";
+
+//echo "Temporary files are [$datFilename] and [$pngFilename]\n";
+
+echo "<br><a href=\"https://panstarrs.atlassian.net/browse/IPP-2244\" target=new><font color = \"blue\">IPP-2244</font></a><br>";
+
+// Start timer
+$start = microtime(true);
+
+$DQarray = array();
+$qry = $db->query($sql);
+if (dberror($qry)) {
+    echo "<b>Error with $sql</b><br>\n";
+    return;
+}
+
+while ($qry->fetchInto($row)) {
+    $DQarray[] = $row;
+}
+
+// Ensure $DQarray is not empty
+if (empty($DQarray)) {
+    echo "<b>Error:</b> Data array is empty.";
+    return; // Stop execution if no data to encode
+}
+
+// Convert data array to JSON for easier handling in JavaScript
+$dataJson = json_encode($DQarray);
+
+if ($dataJson === false) {
+    echo "<b>Error encoding JSON:</b> " . json_last_error_msg(); // Display any JSON encoding errors
+    return; // Stop execution if JSON encoding fails
+}
+
+echo "<script>console.log(" . json_encode($dataJson) . ");</script>"; // Log JSON output to console for debugging
+
+echo <<<HTML
+<!-- Attempt to load Google Charts library from the Google CDN -->
+<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js" onerror="loadLocalGoogleCharts()"></script>
+
+<script type="text/javascript">
+    // Check if Google Charts library loaded successfully
+    window.addEventListener("load", function() {
+        if (typeof google === "undefined" || typeof google.charts === "undefined") {
+            loadLocalGoogleCharts();
+        }
+    });
+
+    // Function to load local version of Google Charts if CDN fails
+    function loadLocalGoogleCharts() {
+        console.warn("Google Charts CDN failed, loading local loader.js instead.");
+        var script = document.createElement("script");
+        script.src = "loader.js"; // Path to your local loader.js file
+        document.head.appendChild(script);
+    }
+</script>
+
+<script type="text/javascript">
+    google.charts.load('current', {packages: ['corechart']});
+
+    // Use the encoded JSON directly in JavaScript
+    const dataArray = JSON.parse('{$dataJson}'); // Directly parse the PHP JSON string
+
+    // draw FWHM vs MJD
+    function drawFWHMChart() {
+        var data = new google.visualization.DataTable();
+            data.addColumn('number', 'MJD');
+            data.addColumn('number', 'FWHM_major');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'FWHM_minor');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'seeing ~ 1"');
+            data.addColumn('number', 'seeing ~ 3"');
+
+        const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id] = row;
+
+            return [
+                parseFloat(mjd),      // Position Angle
+                parseFloat(iq_fwhm_maj),         // RA_offset (AST_R0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,
+                parseFloat(iq_fwhm_min),        // Dec_offset (AST_D0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,
+                4, 
+                12
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'FWHM (MJD)',
+            titleTextStyle: {color: 'black', fontSize: 15},
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, 
+                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, 
+                2: { color: 'red', lineWidth: 2, pointSize: 0 }, 
+                3: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }  
+            },
+            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: {count: -1}
+            },
+            vAxis: {
+                title: 'FWHM (pixels)',
+            },
+            tooltip: { isHtml: true }, // Render tooltips as HTML
+            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
+            fontSize: 15,
+        };
+
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_fwhm'));
+        chart.draw(data, options);
+    }
+
+    // draw zoomed zerpoint vs mjd
+    function drawZOOMZPTChart() {
+        var data = new google.visualization.DataTable();
+        data.addColumn('number', 'MJD');
+    
+        // Add columns for each filter type to handle separate colors
+        data.addColumn('number', 'g (24.563, 25.013)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'r (24.750, 24.840)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'i (24.611, 24.711)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'z (24.240, 24.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'y (23.320, 23.570)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'w (26.000, 26.300)');
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+    
+        const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id] = row;
+    
+            // Initialize all filter values as null
+            let zp_g = null, zp_r = null, zp_i = null, zp_z = null, zp_y = null, zp_w = null;
+    
+            // Set the zeropoint offset based on filter and assign it to the correct series
+            switch (filter[0]) {
+                case 'g':
+                    zp_g = zpt_obs - 24.563;
+                    break;
+                case 'r':
+                    zp_r = zpt_obs - 24.750;
+                    break;
+                case 'i':
+                    zp_i = zpt_obs - 24.611;
+                    break;
+                case 'z':
+                    zp_z = zpt_obs - 24.240;
+                    break;
+                case 'y':
+                    zp_y = zpt_obs - 23.320;
+                    break;
+                case 'w':
+                    zp_w = zpt_obs - 26.000;
+                    break;
+            }
+    
+            return [
+                parseFloat(mjd), // MJD value
+                zp_g, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_g - zpt_stdev), parseFloat(zp_g - zpt_stdev*-1),
+                zp_r, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_r - zpt_stdev), parseFloat(zp_r - zpt_stdev*-1),
+                zp_i, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_i - zpt_stdev), parseFloat(zp_i - zpt_stdev*-1),
+                zp_z, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_z - zpt_stdev), parseFloat(zp_z - zpt_stdev*-1),
+                zp_y, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_y - zpt_stdev), parseFloat(zp_y - zpt_stdev*-1),
+                zp_w, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_w - zpt_stdev), parseFloat(zp_w - zpt_stdev*-1),
+    
+            ];
+        });
+    
+        data.addRows(rows);
+    
+        const options = {
+            title: 'Zeropoint zoom-in (MJD)',
+            titleTextStyle: { color: 'black', fontSize: 15 },
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#00f000', pointSize: 5, pointShape: 'circle',   dataOpacity: .6},  // 'g' filter
+                1: { color: '#f00000', pointSize: 5, pointShape: 'triangle', dataOpacity: .6},  // 'r' filter
+                2: { color: '#f05000', pointSize: 5, pointShape: 'square',   dataOpacity: .6},  // 'i' filter
+                3: { color: '#0050a0', pointSize: 5, pointShape: 'diamond',  dataOpacity: .6},  // 'z' filter
+                4: { color: '#ffe000', pointSize: 5, pointShape: 'star',     dataOpacity: .6},  // 'y' filter
+                5: { color: '#808080', pointSize: 5, pointShape: 'polygon',  dataOpacity: .6},  // 'w' filter
+            },
+            intervals: { color: 'red', lineWidth: 1, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: { count: -1 }
+            },
+            vAxis: {
+                title: 'Zeropoint (mag)',
+                viewWindow: {   min: -1.00, max: .5    },
+            },
+            tooltip: { isHtml: true },
+            chartArea: { left: '7%', top: 60, right: '4%', bottom: 50 },
+            fontSize: 15,
+        };
+    
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_zoomzpt'));
+        chart.draw(data, options);
+    }
+
+    // draw zeropoint vs mjd
+    function drawZPTChart() {
+        var data = new google.visualization.DataTable();
+        data.addColumn('number', 'MJD');
+    
+        // Add columns for each filter type to handle separate colors
+        data.addColumn('number', 'g' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'r' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'i' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'z' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'y' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn('number', 'w' );
+        data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
+        data.addColumn({type: 'number', role: 'interval'});
+        data.addColumn({type: 'number', role: 'interval'});
+    
+        // Count occurrences of each filter
+        const filterCounts = { g: 0, r: 0, i: 0, z: 0, y: 0, w: 0 };
+
+        const rows = dataArray.map(row => {
+            const [timestamp, mjd, filter, comment, ra, dec, exp_name, alt, az, iq_fwhm_maj, iq_fwhm_min, zpt_obs, zpt_stdev, exp_id] = row;
+    
+            // Initialize all filter values as null
+            let zp_g = null, zp_r = null, zp_i = null, zp_z = null, zp_y = null, zp_w = null;
+
+            // Increment the count for the filter
+            if (filterCounts.hasOwnProperty(filter[0])) {
+                filterCounts[filter[0]] += 1;
+            }
+    
+            // Set the zeropoint offset based on filter and assign it to the correct series
+            switch (filter[0]) {
+                case 'g':
+                    zp_g = zpt_obs - 0.0;
+                    break;
+                case 'r':
+                    zp_r = zpt_obs - 0.0;
+                    break;
+                case 'i':
+                    zp_i = zpt_obs - 0.0;
+                    break;
+                case 'z':
+                    zp_z = zpt_obs - 0.0;
+                    break;
+                case 'y':
+                    zp_y = zpt_obs - 0.0;
+                    break;
+                case 'w':
+                    zp_w = zpt_obs - 0.0;
+                    break;
+            }
+    
+            return [
+                parseFloat(mjd), // MJD value
+                zp_g, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_g - zpt_stdev), parseFloat(zp_g - zpt_stdev*-1),
+                zp_r, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_r - zpt_stdev), parseFloat(zp_r - zpt_stdev*-1),
+                zp_i, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_i - zpt_stdev), parseFloat(zp_i - zpt_stdev*-1),
+                zp_z, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_z - zpt_stdev), parseFloat(zp_z - zpt_stdev*-1),
+                zp_y, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_y - zpt_stdev), parseFloat(zp_y - zpt_stdev*-1),
+                zp_w, "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>HST: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment,  parseFloat(zp_w - zpt_stdev), parseFloat(zp_w - zpt_stdev*-1),
+    
+            ];
+        });
+    
+        data.addRows(rows);
+
+        // Include counts in the title using string concatenation
+        const countsTitle = 'Zeropoint (MJD) g: ' + filterCounts.g + ', r: ' + filterCounts.r + ', i: ' + filterCounts.i + ', z: ' + filterCounts.z + ', y: ' + filterCounts.y + ', w: ' + filterCounts.w;
+        
+
+        console.log(countsTitle);
+
+        const options = {
+            title: countsTitle,
+            titleTextStyle: { color: 'black', fontSize: 15 },
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#00f000', pointSize: 5, pointShape: 'circle',   dataOpacity: .6},  // 'g' filter
+                1: { color: '#f00000', pointSize: 5, pointShape: 'triangle', dataOpacity: .6},  // 'r' filter
+                2: { color: '#f05000', pointSize: 5, pointShape: 'square',   dataOpacity: .6},  // 'i' filter
+                3: { color: '#0050a0', pointSize: 5, pointShape: 'diamond',  dataOpacity: .6},  // 'z' filter
+                4: { color: '#ffe000', pointSize: 5, pointShape: 'star',     dataOpacity: .6},  // 'y' filter
+                5: { color: '#808080', pointSize: 5, pointShape: 'polygon',  dataOpacity: .6},  // 'w' filter
+            },
+            intervals: { color: 'red', lineWidth: 1, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: { count: -1 }
+            },
+            vAxis: {
+                title: 'Zeropoint (mag)'
+            },
+            tooltip: { isHtml: true },
+            chartArea: { left: '7%', top: 60, right: '4%', bottom: 50 },
+            fontSize: 15,
+        };
+    
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_zpt'));
+        chart.draw(data, options);
+    }
+
+    google.charts.setOnLoadCallback(drawFWHMChart);
+    google.charts.setOnLoadCallback(drawZPTChart);
+    google.charts.setOnLoadCallback(drawZOOMZPTChart);
+</script>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_zpt" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_zoomzpt" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_fwhm" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+HTML;
+
+// End timer
+$total_time = round(microtime(true) - $start, 3);
+echo "<center>Loading plot in $total_time seconds<br></center>";
+
+menu_end();
+
+?>
Index: /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotPointing.php
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotPointing.php	(revision 42751)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/raw/scatterPlotPointing.php	(revision 42751)
@@ -0,0 +1,715 @@
+<?php 
+
+include 'ipp.php';
+delete_old_tmp_files();
+
+$ID = checkID ();
+
+// require an explicit project
+if (! $ID['proj']) { projectform ($ID); }
+
+$db = dbconnect($ID['proj']);
+
+if ($ID['menu']) {
+  $myMenu = $ID['menu'];
+} else {
+  $myMenu = "ipp.plots.dat";
+}
+
+menu($myMenu, 'Pointing', 'ipp.css', $ID['link'], $ID['proj']);
+
+echo "<p> Pointing status </p>";
+
+// set up the form
+echo "<form action=\"scatterPlotPointing.php\" method=\"POST\">\n";
+
+$restricted = 0;
+
+// define restrictiosn to the queries
+// ** TABLE RESTRICTIONS **
+$WHERE = "WHERE camRun.state = 'full' AND chipRun.exp_id = rawExp.exp_id AND camRun.chip_id = chipRun.chip_id AND camProcessedExp.cam_id = camRun.cam_id AND camProcessedExp.fault = 0";
+$WHERE = check_restrict ('rawExp.exp_name', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.exp_id', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.telescope', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.camera', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.dateobs', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('camRun.label', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.ra', $WHERE, 'min', 0.017453);
+$WHERE = check_restrict ('rawExp.ra', $WHERE, 'max', 0.017453);
+$WHERE = check_restrict ('rawExp.decl', $WHERE, 'min', 0.017453);
+$WHERE = check_restrict ('rawExp.decl', $WHERE, 'max', 0.017453);
+$WHERE = check_restrict ('rawExp.comment', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.object', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.filter', $WHERE, 'string', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.exp_time', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.airmass', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.bg', $WHERE, 'max', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'value', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'min', 1.0);
+$WHERE = check_restrict ('rawExp.bg_stdev', $WHERE, 'max', 1.0);
+
+if ($restricted == 0) {//Don't select anything
+  if ($WHERE == "") {
+    $WHERE = "WHERE (0 > 1)";
+  } else {
+    $WHERE = "WHERE (0 > 1)";
+  }
+}
+
+// get the result table count
+$sql = "SELECT count(*) FROM camRun, chipRun, rawExp, camProcessedExp $WHERE";
+
+$qry = $db->query($sql);
+if (dberror($qry)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table count</b><br>\n";
+  echo "<br><small><b> count query : $sql </b></small><br>\n";
+  menu_end();
+}
+if (!dbFetchInto($qry, $row)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table count</b><br>\n";
+  echo "<br><small><b> count query : $sql </b></small><br>\n";
+  menu_end();
+}
+$nValues = $row[0];
+
+// group number of filters
+$sql = "SELECT count(*), filter FROM camRun, chipRun, rawExp, camProcessedExp $WHERE group by filter";
+$filterCounts = array('g' => 0, 'r' => 0, 'i' => 0, 'z' => 0, 'y' => 0, 'w' => 0);
+
+// Accumulate counts by filter
+$qry = $db->query($sql);
+while ($qry->fetchInto($dat)) {
+    $filter = strtolower(substr($dat[1], 0, 1)); // Get the first letter of the filter
+    $filterCounts[$filter] += $dat[0];
+}
+
+// maximum number of query items
+$qmax   = 10000;
+
+// Display message based on count
+if ($nValues > $qmax) {
+  echo "<b>$nValues match selection, but only showing $qmax exposures randomly</b><br>\n";
+} else {
+  echo "<b>$nValues match selection</b><br>\n";
+}
+
+// Display filter counts
+echo "<b>Filter counts: g: {$filterCounts['g']}, r: {$filterCounts['r']}, i: {$filterCounts['i']}, z: {$filterCounts['z']}, y: {$filterCounts['y']}, w: {$filterCounts['w']}</b><br>";
+
+// Call the function and display the result, function in ipp.php
+$mjdday = getMJD();
+echo "<b>MJD today: $mjdday</b><br><br>";
+
+// Modify the second query to limit to $qmax if $nValues is larger than $qmax
+$limitClause = ($nValues > $qmax) ? "ORDER BY RAND() LIMIT $qmax" : "";
+
+$sql = "SELECT SUBTIME(dateobs, '10:00:00') AS time, AST_R0, AST_D0, round(( 367*YEAR(dateobs)- FLOOR((7 * (YEAR(dateobs) + FLOOR((MONTH(dateobs) + 9) / 12))) / 4) + FLOOR(275 * MONTH(dateobs) / 9) + DAY(dateobs) + 1721013.5 + (HOUR(dateobs) / 24.0) + (MINUTE(dateobs) / 1440.0) + (SECOND(dateobs) / 86400.0) - 2400000.5), 5) AS MJD, filter, exp_time, comment, ra*180/pi() as RA, decl*180/pi() as DECL, AST_RS, AST_DS, AST_T0, posang, exp_name, alt, az, rawExp.exp_id FROM camRun, chipRun, rawExp, camProcessedExp $WHERE $limitClause";
+$qry = $db->query($sql);
+
+if (dberror($qry)) {
+  echo "<b>error reading camRun, chipRun, rawExp, camProcessedExp, chipProcessedImfile table</b><br>\n";
+  echo "<br><small><b> table query : $sql </b></small><br>\n";
+  menu_end();
+}
+
+// ** HEAD CODE **
+
+// ** BUTTON RESTRICTIONS **
+$buttonLink = button_restrict_string ('rawExp.exp_name', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.exp_id', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.telescope', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.camera', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.dateobs', $buttonLink);
+$buttonLink = button_restrict_string ('camRun.label', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.ra', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.decl', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.comment', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.object', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.filter', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.exp_time', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.airmass', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.bg', $buttonLink);
+$buttonLink = button_restrict_string ('rawExp.bg_stdev', $buttonLink);
+$buttonLink = button_restrict_min ('rawExp.bg_stdev', $buttonLink);
+$buttonLink = button_restrict_max ('rawExp.bg_stdev', $buttonLink);
+navigate_buttons ($rowStart, $rowLast, $dTABLE, $rowTotal, $buttonLink, $ID, 'scatterPlotPointing.php');
+
+echo "&nbsp; : &nbsp; or enter start row: <input type=\"text\" name=\"from\" size=\"5\" value=\"$rowStart\">\n";
+
+// set up the table
+echo "<table class=list>\n";
+
+// echo "<tr><td></td>\n"; // first field is a label set below for the query rows only
+// ** TABLE HEADER **
+echo "<tr><td></td>\n";
+write_header_cell ("list", "Exp Name");
+write_header_cell ("list", "Exp ID");
+write_header_cell ("list", "Telescope");
+write_header_cell ("list", "Camera");
+write_header_cell ("list", "Date/Time");
+write_header_cell ("list", "Label");
+write_header_cell ("list", "RA");
+write_header_cell ("list", "DEC");
+write_header_cell ("list", "Comment");
+write_header_cell ("list", "Object");
+write_header_cell ("list", "FILTER");
+write_header_cell ("list", "exp_time");
+write_header_cell ("list", "airmass");
+write_header_cell ("list", "backgnd");
+write_header_cell ("list", "stdev");
+echo "</tr>\n";
+echo "<tr><td></td>\n";
+write_sort_cell ("list", "rawExp.exp_name", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.exp_id", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.telescope", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.camera", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.dateobs", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "camRun.label", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.ra", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.decl", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.comment", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.object", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.filter", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.exp_time", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.airmass", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.bg", $buttonLink, $ID, 'scatterPlotPointing.php');
+write_sort_cell ("list", "rawExp.bg_stdev", $buttonLink, $ID, 'scatterPlotPointing.php');
+echo "</tr>\n";
+// echo "</tr>\n";
+
+// query restriction form
+// echo "<tr>\n";
+// echo "<td class=list> <input type=\"text\" name=\"expID\"></td>\n";
+// ** TABLE QUERY **
+echo "<tr><td>&ge;</td>\n";
+write_query_row ('rawExp.exp_name', 5, 'string');
+write_query_row ('rawExp.exp_id', 5, 'min');
+write_query_row ('rawExp.telescope', 10, 'string');
+write_query_row ('rawExp.camera', 10, 'string');
+write_query_row ('rawExp.dateobs', 19, 'min');
+write_query_row ('camRun.label', 10, 'string');
+write_query_row ('rawExp.ra', 8, 'min');
+write_query_row ('rawExp.decl', 8, 'min');
+write_query_row ('rawExp.comment', 65, 'string');
+write_query_row ('rawExp.object', 8, 'string');
+write_query_row ('rawExp.filter', 10, 'string');
+write_query_row ('rawExp.exp_time', 5, 'min');
+write_query_row ('rawExp.airmass', 5, 'min');
+write_query_row ('rawExp.bg', 5, 'min');
+write_query_row ('rawExp.bg_stdev', 5, 'min');
+echo "</tr><tr><td>&le;</td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.exp_id', 5, 'max');
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.dateobs', 19, 'max');
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.ra', 8, 'max');
+write_query_row ('rawExp.decl', 8, 'max');
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+echo "<td> &nbsp; </td>\n";
+write_query_row ('rawExp.exp_time', 5, 'max');
+write_query_row ('rawExp.airmass', 5, 'max');
+write_query_row ('rawExp.bg', 5, 'max');
+write_query_row ('rawExp.bg_stdev', 5, 'max');
+echo "</tr>\n";
+// echo "</tr>\n";
+
+// query restriction form
+// echo "<tr>\n";
+// echo "<td class=list> <input type=\"text\" name=\"expID\"></td>\n";
+// TABLE QUERY 
+// echo "</tr>\n";
+
+// close the table and form
+echo "</table>\n";
+echo "<input type=\"submit\" name=\"constraints\" value=\"refine search\">\n";
+$pass = $ID['pass'];
+$proj = $ID['proj'];
+$menu = $ID['menu'];
+echo "<input type=\"hidden\" name=\"pass\" value=\"$pass\">\n";
+echo "<input type=\"hidden\" name=\"proj\" value=\"$proj\">\n";
+echo "<input type=\"hidden\" name=\"menu\" value=\"$menu\">\n";
+echo "</form>\n";
+
+if ($row[0] == 0) {
+  menu_end();
+}
+
+//$datFilename = tempnam("/tmp", "dvodat.");
+//$pngFilename = $datFilename.".png";
+//
+//$datfile = fopen($datFilename, "w");
+//chmod($datFilename, 0777);
+//
+//// output the results to tmpfile
+//while (dbFetchInto($qry, $row)) {
+//  $line = "";
+//  foreach ($row as $i => $value) {
+//    switch ($value) {
+//    case 'g.00002':
+//      $filter = 1;
+//      break;
+//    case 'r.00002':
+//      $filter = 2;
+//      break;
+//    case 'i.00002':
+//      $filter = 3;
+//      break;
+//    case 'z.00002':
+//      $filter = 4;
+//      break;
+//    case 'y.00002':
+//      $filter = 5;
+//      break;
+//    case 'w.00002':
+//      $filter = 6;
+//      break;
+//    case 'g.00000':
+//      $filter = 1;
+//      break;
+//    case 'r.00000':
+//      $filter = 2;
+//      break;
+//    case 'i.00000':
+//      $filter = 3;
+//      break;
+//    case 'z.00000':
+//      $filter = 4;
+//      break;
+//    case 'y.00000':
+//      $filter = 5;
+//      break;
+//    case 'w.00000':
+//      $filter = 6;
+//      break;
+//    case 'OPEN':
+//      $filter = 0;
+//      break;
+//    case 'g':
+//      $filter = 1;
+//      break;
+//    case 'r':
+//      $filter = 2;
+//      break;
+//    case 'i':
+//      $filter = 3;
+//      break;
+//    case 'z':
+//      $filter = 4;
+//      break;
+//    case 'y':
+//      $filter = 5;
+//      break;
+//    case 'w':
+//      $filter = 6;
+//      break;
+//    default:
+//      $filter = $value;
+//      break;
+//    }
+//    $line .= "$filter ";
+//  }
+//  if (preg_match('/^[ \t]*$/', $line) == 0) {//Don't write empty lines
+//    $line = preg_replace('/[ \t]*$/', '', $line);
+//    fwrite ($datfile, $line."\n");
+//  }
+//}
+//fclose($datfile);
+//
+//echo "<img src=\"skyplot.php?input=$datFilename&output=$pngFilename&title='Sky_Plot_Raw'\"><br>\n";
+//
+// ** TAIL CODE **
+
+echo "<small> WHERE: $WHERE<br><br></small>\n";
+echo "<small> SQL: $sql<br><br></small>\n";
+
+//echo "Temporary files are [$datFilename] and [$pngFilename]\n";
+
+echo "<br><a href=\"https://panstarrs.atlassian.net/browse/IPP-2244\" target=new><font color = \"blue\">IPP-2244</font></a><br>";
+
+// Start timer
+$start = microtime(true);
+
+$DQarray = array();
+$qry = $db->query($sql);
+if (dberror($qry)) {
+    echo "<b>Error with $sql</b><br>\n";
+    return;
+}
+
+while ($qry->fetchInto($row)) {
+    $DQarray[] = $row;
+}
+
+// Ensure $DQarray is not empty
+if (empty($DQarray)) {
+    echo "<b>Error:</b> Data array is empty.";
+    return; // Stop execution if no data to encode
+}
+
+// Convert data array to JSON for easier handling in JavaScript
+$dataJson = json_encode($DQarray);
+
+if ($dataJson === false) {
+    echo "<b>Error encoding JSON:</b> " . json_last_error_msg(); // Display any JSON encoding errors
+    return; // Stop execution if JSON encoding fails
+}
+
+echo "<script>console.log(" . json_encode($dataJson) . ");</script>"; // Log JSON output to console for debugging
+
+echo <<<HTML
+<!-- Attempt to load Google Charts library from the Google CDN -->
+<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js" onerror="loadLocalGoogleCharts()"></script>
+
+<script type="text/javascript">
+    // Check if Google Charts library loaded successfully
+    window.addEventListener("load", function() {
+        if (typeof google === "undefined" || typeof google.charts === "undefined") {
+            loadLocalGoogleCharts();
+        }
+    });
+
+    // Function to load local version of Google Charts if CDN fails
+    function loadLocalGoogleCharts() {
+        console.warn("Google Charts CDN failed, loading local loader.js instead.");
+        var script = document.createElement("script");
+        script.src = "loader.js"; // Path to your local loader.js file
+        document.head.appendChild(script);
+    }
+</script>
+
+<script type="text/javascript">
+    google.charts.load('current', {packages: ['corechart']});
+
+    // Use the encoded JSON directly in JavaScript
+    const dataArray = JSON.parse('{$dataJson}'); // Directly parse the PHP JSON string
+
+    // draw pointing vs mjd
+    function drawMJDChart() {
+        var data = new google.visualization.DataTable();
+            data.addColumn('number', 'MJD');
+            data.addColumn('number', 'RA_offset (AST_R0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'Dec_offset (AST_D0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', '20 TP unit ~5.1"');
+            data.addColumn('number', '-20 TP unit ~5.1"');
+        
+        const rows = dataArray.map(row => {
+            const [timestamp, ra_offset, dec_offset, mjd, filter, exp_time, comment, ra, dec, ra_offset_sig, dec_offset_sig, boresite_ang, position_ang, exp_name, alt, az, exp_id] = row;
+           
+            return [
+                parseFloat(mjd),               // MJD
+                parseFloat(ra_offset),         // RA_offset (AST_R0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+                parseFloat(dec_offset),        // Dec_offset (AST_D0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+                20,                            // Dummy value for 20 TP unit
+                -20                            // Dummy value for -20 TP unit
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'Pointing Offset (MJD)',
+            titleTextStyle: {color: 'black', fontSize: 15},
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
+                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
+                2: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }, // Line at y = 20
+                3: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }  // Line at y = -20
+            },
+            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: {count: -1}
+            },
+            vAxis: {
+                title: 'Offset (TP units)',
+            },
+            tooltip: { isHtml: true }, // Render tooltips as HTML
+            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
+            fontSize: 15,
+        };
+
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_mjd'));
+        chart.draw(data, options);
+    }
+
+    // draw pointing scatter
+    function drawSIGChart() {
+        var data = new google.visualization.DataTable();
+            data.addColumn('number', 'MJD');
+            data.addColumn('number', 'RA_offset_scatter (AST_RS)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'Dec_offset_scatter (AST_DS)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+        
+        const rows = dataArray.map(row => {
+            const [timestamp, ra_offset, dec_offset, mjd, filter, exp_time, comment, ra, dec, ra_offset_sig, dec_offset_sig, boresite_ang, position_ang, exp_name, alt, az, exp_id] = row;
+           
+            return [
+                parseFloat(mjd),               // MJD
+                parseFloat(ra_offset_sig),     // RA_offset_scatter (AST_RS)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+                parseFloat(dec_offset_sig),    // Dec_offset_scatter (AST_DS)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'Pointing Offset Scatter (MJD)',
+            titleTextStyle: {color: 'black', fontSize: 15},
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
+                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
+                2: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }, // Line at y = 20
+                3: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }  // Line at y = -20
+            },
+            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
+            hAxis: {
+                title: 'MJD',
+                gridlines: {count: -1}
+            },
+            vAxis: {
+                title: 'Offset Scatter (TP units)',
+            },
+            tooltip: { isHtml: true }, // Render tooltips as HTML
+            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
+            fontSize: 15,
+        };
+
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_sig'));
+        chart.draw(data, options);
+    }
+
+    // position angle
+    function drawPOSChart() {
+        var data = new google.visualization.DataTable();
+            data.addColumn('number', 'MJD');
+            data.addColumn('number', 'RA_offset (AST_R0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'Dec_offset (AST_D0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+        
+        const rows = dataArray.map(row => {
+            const [timestamp, ra_offset, dec_offset, mjd, filter, exp_time, comment, ra, dec, ra_offset_sig, dec_offset_sig, boresite_ang, position_ang, exp_name, alt, az, exp_id] = row;
+           
+            return [
+                parseFloat(position_ang),      // Position Angle
+                parseFloat(ra_offset),         // RA_offset (AST_R0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+                parseFloat(dec_offset),        // Dec_offset (AST_D0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'Pointing Offset (Position Angle)',
+            titleTextStyle: {color: 'black', fontSize: 15},
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            // pointSize: 5, // Point size for scatter plot
+            // lineWidth: 2,
+            series: {
+                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
+                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
+            },
+            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
+            hAxis: {
+                title: 'Position Angle',
+                gridlines: {count: -1}
+            },
+            vAxis: {
+                title: 'Offset (TP units)',
+            },
+            tooltip: { isHtml: true }, // Render tooltips as HTML
+            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
+            fontSize: 15,
+        };
+
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_pos'));
+        chart.draw(data, options);
+    }
+
+    function drawALTChart() {
+        var data = new google.visualization.DataTable();
+            data.addColumn('number', 'Altitute');
+            data.addColumn('number', 'RA_offset (AST_R0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'Dec_offset (AST_D0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+        
+        const rows = dataArray.map(row => {
+            const [timestamp, ra_offset, dec_offset, mjd, filter, exp_time, comment, ra, dec, ra_offset_sig, dec_offset_sig, boresite_ang, position_ang, exp_name, alt, az, exp_id] = row;
+           
+            return [
+                parseFloat(alt),      // Position Angle
+                parseFloat(ra_offset),         // RA_offset (AST_R0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+                parseFloat(dec_offset),        // Dec_offset (AST_D0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'Pointing Offset (Altitude)',
+            titleTextStyle: {color: 'black', fontSize: 15},
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
+                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
+            },
+            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
+            hAxis: {
+                title: 'Altitude',
+                gridlines: {count: -1}
+            },
+            vAxis: {
+                title: 'Offset (TP units)',
+            },
+            tooltip: { isHtml: true }, // Render tooltips as HTML
+            //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
+            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
+            fontSize: 15,
+        };
+
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_alt'));
+        chart.draw(data, options);
+    }
+
+    function drawAZChart() {
+        var data = new google.visualization.DataTable();
+            data.addColumn('number', 'Azumith');
+            data.addColumn('number', 'RA_offset (AST_R0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+            data.addColumn('number', 'Dec_offset (AST_D0)');
+            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
+        
+        const rows = dataArray.map(row => {
+            const [timestamp, ra_offset, dec_offset, mjd, filter, exp_time, comment, ra, dec, ra_offset_sig, dec_offset_sig, boresite_ang, position_ang, exp_name, alt, az, exp_id] = row;
+           
+            return [
+                parseFloat(az),      // Position Angle
+                parseFloat(ra_offset),         // RA_offset (AST_R0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+                parseFloat(dec_offset),        // Dec_offset (AST_D0)
+                "expname: "+exp_name+"<br>exp_id: "+exp_id+"<br>timestamp: "+timestamp+"<br>RA: "+ra+"<br>DEC: "+dec+"<br>filter: "+filter+"<br>comment: "+comment, 
+            ];
+        });
+
+        data.addRows(rows);
+
+        const options = {
+            title: 'Pointing Offset (Azumith)',
+            titleTextStyle: {color: 'black', fontSize: 15},
+            width: '100%',
+            height: 480,
+            legend: { position: 'top', alignment: 'center' },
+            series: {
+                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
+                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
+            },
+            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
+            hAxis: {
+                title: 'Azumith',
+                gridlines: {count: -1}
+            },
+            vAxis: {
+                title: 'Offset (TP units)',
+            },
+            tooltip: { isHtml: true }, // Render tooltips as HTML
+            //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
+            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
+            fontSize: 15,
+        };
+
+        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_az'));
+        chart.draw(data, options);
+    }
+
+    google.charts.setOnLoadCallback(drawMJDChart);
+    google.charts.setOnLoadCallback(drawSIGChart);
+    google.charts.setOnLoadCallback(drawPOSChart);
+    google.charts.setOnLoadCallback(drawALTChart);
+    google.charts.setOnLoadCallback(drawAZChart);
+</script>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_mjd" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_sig" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_pos" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_alt" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+
+<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
+    <div id="dq_div_az" style="width:1240px;"></div>
+    <div class="overlay" style="position: absolute; width: 800px; bottom: 60px; left: 85px;"></div>
+</div>
+HTML;
+
+// End timer
+$total_time = round(microtime(true) - $start, 3);
+echo "<center>Loading plot in $total_time seconds<br></center>";
+
+menu_end();
+
+?>
+
+
+
Index: /branches/eam_branches/ipp-20230313/ippMonitor/raw/storage.php
===================================================================
--- /branches/eam_branches/ipp-20230313/ippMonitor/raw/storage.php	(revision 42750)
+++ /branches/eam_branches/ipp-20230313/ippMonitor/raw/storage.php	(revision 42751)
@@ -23,5 +23,5 @@
 echo "<table border=\"0\">";
 echo "<tr>";
-echo "  <td style=width:1000px>";
+echo "  <td style=width:1200px>";
 echo "  <h1 align=\"middle\">Storage status</h1>";
 # storage timeseries
@@ -42,5 +42,4 @@
 /////////////////////////////////////////////////////////////////////////////
 
-
 ###########################################################################
 #
@@ -49,14 +48,9 @@
 ###########################################################################
 function getHosts($db) {
-    // timer start
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $start = $time;
-
-    #echo "<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>";
+    $start = microtime(true);
+
     echo "<script type=\"text/javascript\" src=\"loader.js\"></script>";
-    echo "<br><div class=\"chartWithOverlay\" style=\"position: relative; width: 640px\">"; 
-    echo "  <div id=\"disk_div\" style=\"width:1000px; height:1600px\"></div>";
+    echo "<br><div class=\"chartWithOverlay\" style=\"position: relative; width: 100%\">";
+    echo "  <div id=\"disk_div\" style=\"width:100%; height:4000px\"></div>";
     echo "  <div class=\"overlay\" style=\"position: absolute; width: 100px; top: 50px; right: 20px;\">";
     echo "    <div style=\"font-size: 12px; height: 14px; border: 1px solid; background-color: #00ff00\"><center>Free</div>";
@@ -68,88 +62,84 @@
     echo "</div>";
 
-    echo "<script type=\"text/javascript\">";
-    echo "google.charts.load('current', {packages: ['corechart', 'bar']});";
-    echo "google.charts.setOnLoadCallback(drawBarColors);";
-    echo "function drawBarColors() {";
-    echo "  var data = google.visualization.arrayToDataTable([";
-    echo "    ['Host', ";
-    echo "     'used', {type: 'string', role: 'style'}, {type: 'string', role: 'tooltip', 'p': {'html': true}}, ";
-    echo "     'free', {type: 'string', role: 'style'}, {type: 'string', role: 'tooltip', 'p': {'html': true}}],";
-
-    $sql = "SELECT host, format(total,1), format(available,2), format(used,2), writable, readable, format(used/total*100,2) FROM hosts order by host";
-    if ($debug) {echo "$sql<br>";}
+    // Set environment variables
+    putenv("PATH=/usr/local/bin:/usr/bin:/bin:/data/ippc65.0/ipp/src/psconfig//ipp-20210708-gentoo.lin64/bin");
+    putenv("PERL5LIB=/data/ippc65.0/ipp/src/psconfig//ipp-20210708-gentoo.lin64/lib");
+
+    $hostnoteall = array();
+    exec("neb-host |cut -b 17-30,86-", $hostnoteall);
+
+    $sql = "SELECT host, format(total, 2), format(available, 2), format(used, 2), writable, readable, format(used/total*100,3) as ratio 
+            FROM hosts 
+            ORDER BY host";
     $qry = $db->query($sql);
-    if (dberror($qry)) {echo "<b>error with $sql </b><br>\n";}
-    # not sure why neb-host doesn't work on ipp113 CCL.20210216
-    exec("neb-host |cut -b 17-30,86-", $hostnoteall);
+
+    if ($qry === false) {
+        echo "<b>Error with SQL query</b><br>";
+        return;
+    }
+
+    $dataRows = array();
     while ($qry->fetchInto($row)) {
-        list($host, $total, $available, $used, $writable, $readable, $ratio) = $row;
-       $hostnotes = preg_grep("/$host/", $hostnoteall);
-       $hostnote = array_values($hostnotes);
-       if ($writable == 1 && $readable == 1) {
-          if ($ratio >= 97) {
-            # space used over limits, up mode (read/write ok).
-            echo "[ \"$host\", ";
-            echo "      $used, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #ff0000;\", \"<i><b>$host: $ratio% of $total TB used</b></i><br>$hostnote[0]\", ";
-            echo " $available, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #00ff00;\", \"<i><b>$host: $available TB free</b></i>\"],";
-          }
-          else {
-            # enough space, up mode (read/write ok).
-            echo "[ \"$host\", ";
-            echo "      $used, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #ffff00;\", \"<i><b>$host: $ratio% of $total TB used</b></i><br>$hostnote[0]\", ";
-            echo " $available, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #00ff00;\", \"<i><b>$host: $available TB free</b></i>\"],";
-         }
-       }
-       else if ($writable == 0 && $readable == 1) {
-          if ($ratio >= 97) {
-            # space used over limits, repair mode (read only).
-            echo "[ \"$host\", ";
-            echo "      $used, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #ff0000;\", \"<i><b>$host: $ratio% of $total TB used<br><font color=red>$hostnote[0]\", ";
-            echo " $available, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #bbbbbb;\", \"<i><b>$host: $available TB free</b></i>\"],";
-          }
-          else {
-            # enough space, but hosts are unstable, repair mode (read only).
-            echo "[ \"$host\", ";
-            echo "      $used, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #ffff00;\", \"<i><b>$host: $ratio% of $total TB used<br>$hostnote[0]\", ";
-            echo " $available, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #bbbbbb;\", \"<i><b>$host: $available TB free</b></i>\"],";
-          }
-       }
-       else {
-            # down mode (can't read or write).
-            echo "[ \"$host\", ";
-            echo "      $used, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #bbbbbb;\", \"<i><b>$host: $ratio% used<br>$hostnote[0]\", ";
-            echo " $available, \"stroke-width: 0.3;\"+\"stroke-color: black;\"+\"color: #bbbbbb;\", \"<i><b>$host: $available TB free</b></i>\"],";
-       }
+        // Access data using numeric indices
+        $host = $row[0]; // ipp071.0
+        $total = $row[1]; // 80.0352
+        $available = $row[2]; // 10.8096
+        $used = $row[3]; // 69.2256
+        $writable = $row[4]; // 0
+        $readable = $row[5]; // 1
+        $ratio = $row[6]; // 86.493950215116
+
+        $hostnotes = preg_grep("/$host/", $hostnoteall);
+        $hostnote = reset($hostnotes);
+
+        $styles = "stroke-width: 0.5; stroke-color: black;";
+        if ($writable == 1 && $readable == 1) {
+            $usedColor = $ratio >= 97 ? "#ff0000" : "#ffff00";
+            $freeColor = "#00ff00";
+        } elseif ($writable == 0 && $readable == 1) {
+            $usedColor = $ratio >= 97 ? "#ff0000" : "#ffff00";
+            $freeColor = "#bbbbbb";
+        } else {
+            $usedColor = $freeColor = "#bbbbbb";
+        }
+
+        $dataRows[] = "[ \"$host\", $used, \"$styles color: $usedColor;\", \"$host: $ratio% of $total TB used<br>$hostnote\", 
+                       $available, \"$styles color: $freeColor;\", \"$host: $available TB free\"]";
     }
-   echo "  ]);";
-   echo "   var options = {";
-   echo "     title: 'Nebulous Disk Use across IPP Clusters',";
-   echo "     titleTextStyle: {color: 'black', fontSize: 15},";
-   echo "     width: '100%',";
-   echo "     height: '100%',";
-   echo "     tooltip: {isHtml: true},";
-   echo "     legend: { position: 'none',";
-   echo "               alignment: 'end',";
-   echo "               maxLines: 3},";
-   echo "     hAxis: {  title: 'Space (TB)',";
-   echo "               gridlines: {count: 10}";
-   echo "     },";
-   echo "     bar: { groupWidth: '95%' },";
-   echo "     chartArea: {left:70, top:30, right:20, bottom:40},";
-   echo "     fontSize: 12,";
-   echo "     isStacked: true";
-   echo "   };";
-   echo "   var chart = new google.visualization.BarChart(document.getElementById('disk_div'));";
-   echo "   chart.draw(data, options);";
-   echo " }";
-   echo "</script>";
-    $time = microtime();
-    $time = explode(' ', $time);
-    $time = $time[1] + $time[0];
-    $finish = $time;
-    $total_time = round(($finish - $start), 3);
-    $start= $finish;
+
+    echo "<script type=\"text/javascript\">
+            google.charts.load('current', {packages: ['corechart', 'bar']});
+            google.charts.setOnLoadCallback(drawBarColors);
+
+            function drawBarColors() {
+                var data = google.visualization.arrayToDataTable([
+                    ['Host', 'Used', {type: 'string', role: 'style'}, {type: 'string', role: 'tooltip', 'p': {'html': true}}, 
+                     'Free', {type: 'string', role: 'style'}, {type: 'string', role: 'tooltip', 'p': {'html': true}}],
+                    " . implode(",\n", $dataRows) . "
+                ]);
+                
+                var options = {
+                    title: 'Nebulous Disk Use across IPP Clusters',
+                    titleTextStyle: {color: 'black', fontSize: 15},
+                    width: '100%',
+                    height: '100%',
+                    tooltip: {isHtml: true},
+                    legend: { position: 'none', alignment: 'end', maxLines: 3 },
+                    hAxis: { title: 'Space (TB)', gridlines: {count: 10} },
+                    bar: { groupWidth: '95%' },
+                    chartArea: {left:100, top:50, right:20, bottom:40},
+                    fontSize: 15,
+                    isStacked: true
+                };
+
+                var chart = new google.visualization.BarChart(document.getElementById('disk_div'));
+                chart.draw(data, options);
+            }
+          </script>";
+
+    $total_time = round(microtime(true) - $start, 3);
     echo "<center>loading in $total_time seconds<br></center>";
 }
+
 
 ###########################################################################
@@ -186,6 +176,6 @@
     #echo "<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>";
     echo "<script type=\"text/javascript\" src=\"loader.js\"></script>";
-    echo "<br><div class=\"chartWithOverlay\" style=\"position: relative; width: 640; height:400\">"; 
-    echo "  <div id=\"space_div\" style=\"width:1000; \"></div>";
+    echo "<br><div class=\"chartWithOverlay\" style=\"position: relative; width: 100%; height:400\">"; 
+    echo "  <div id=\"space_div\" style=\"width:100%; \"></div>";
     echo "  <div class=\"overlay\" style=\"position: absolute; width: 400px; bottom: 60px; left: 85px;\">";
     echo "    <div style=\"font-size: 16px; color:#0000ff; background-color:#ffffff\"><b>ipp + ippb nodes: $ippusable + $ippbusable TB (latest usable)</b></div>";
