IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 43071


Ignore:
Timestamp:
Jul 13, 2026, 4:28:09 PM (4 days ago)
Author:
cclin33
Message:

update ping vxlan

Location:
trunk/ippMonitor
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/ippMonitor/config.dat.in

    r42384 r43071  
    121121$HOST_MAILMAN  = "";
    122122$LABEL_MAILMAN  = "";
     123
     124$HOST_ITCVXLAN  = "";
     125$LABEL_ITCVXLAN  = "";
     126
     127$HOST_ITCVXLAN_BACKUP  = "";
     128$LABEL_ITCVXLAN_BACKUP  = "";
     129
     130$HOST_ATRCVXLAN  = "";
     131$LABEL_ATRCVXLAN  = "";
  • trunk/ippMonitor/configure.tcsh

    r42384 r43071  
    228228cat tmp.1           | sed "s|@WWWBIN@|$wwwbin|"  > tmp.2
    229229cat tmp.2           | sed "s|@LIBDIR@|$libdir|"  > tmp.1
    230 cat tmp.1           | sed "s|@PERLLIB@|$libdir|" > tmp.2
     230cat tmp.1           | sed "s|@PERLLIB@|$libdir|g" > tmp.2
    231231cat tmp.2           | sed "s|@SITE@|$site|"      > tmp.1
    232232cat tmp.1           | sed "s|@DBI@|$DBI|"        > tmp.2
  • trunk/ippMonitor/czartool/czarpoll.pl

    r42972 r43071  
    414414        # check ippdb host IPP-2338
    415415        print "* Checking ippdb hosts\n";
    416         my @ippdb_hosts = qw(ipphome2 ipphome3 ippdb01 ippdb05 ippdb06 ippdb09 ippdb11 ippdb12 ippdb13 ippdb14);
     416        my @ippdb_hosts = qw(ipphome2 ipphome3 ippdb01 ippdb05 ippdb06 ippdb08 ippdb11 ippdb12 ippdb13 ippdb14);
    417417        if($dbupdate == 1) {check_disk_usage_and_update($czarDb, @ippdb_hosts);}
    418418
  • trunk/ippMonitor/raw/czartool_labels.php

    r42972 r43071  
    349349    //showPingStatus($HOST_CONFLUENCE, $LABEL_CONFLUENCE);
    350350    showPingStatus($HOST_MAILMAN, $LABEL_MAILMAN);
     351    showPingStatus($HOST_ITCVXLAN, $LABEL_ITCVXLAN);
     352    showPingStatus($HOST_ITCVXLAN_BACKUP, $LABEL_ITCVXLAN_BACKUP);
     353    showPingStatus($HOST_ATRCVXLAN, $LABEL_ATRCVXLAN);
    351354
    352355    // end time
  • trunk/ippMonitor/raw/dataquality.php

    r42972 r43071  
    7272
    7373echo getDataQuality($projectdb, $range, $proj);
     74echo "<div class=\"chartWithOverlay\" style=\"position: relative; width: 100%; height:200px;\"></div>";
    7475
    7576menu_end();
  • trunk/ippMonitor/raw/functions.php

    r42972 r43071  
    283283        cam_id         : \${row.cam_id}<br>
    284284        moon_angle     : \${row.moon_angle}<br>
    285         raw_chips      : \${row.n_raw}<br>
    286         good_chips     : \${row.g_chips}<br>
     285        n_chips        : \${Number(row.null_bg) + Number(row.good_chip)}<br>
     286        good_phot      : \${row.good_phot}<br>
     287        good_astro     : \${row.good_astro}<br>
     288        null_bg        : \${row.null_bg}<br>
     289        poor_chips     : \${row.poor_chip}<br>
    287290        comment        : \${row.comment}<br>
     291        <img src="http://ippmonitor.ipp.ifa.hawaii.edu/ippMonitor/getimage.php?name=\${row.image_path}&rule=PPIMAGE.JPEG2&camera=${proj}&class_id=NONE">
    288292    `;
    289293}
     
    302306
    303307    // testing day
    304     //$mjdDay = 60945;
    305308    $mjdDay  = getMJD();
     309    //$mjdDay = 61109;
    306310    $mjdDay_yearback = $mjdDay - 366;
    307311    $mjdDay_monthback = $mjdDay - 32;
     
    335339    $stmt->execute([':expname' => $expname]);
    336340    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    337 //    if (!empty($row['min_exp_id'])) {
    338 //        $min_exp_id = $row['min_exp_id'];
    339 //    } else {
    340 //        echo "<center><b>No results found for min_exp_id</b></center>";
    341 //    }
    342 
    343341    if (!empty($row['min_exp_id'])) {
    344342        $min_exp_id = $row['min_exp_id'];
    345         echo "<center><b>min_exp_id:$min_exp_id $mjdDay_monthback $mjdDay</b></center>";
     343        echo "<center><b>min_exp_id:$min_exp_id month:$mjdDay_monthback today:$mjdDay</b></center>";
    346344    } else {
    347         echo "<center><b>No results found for min_exp_id:$min_exp_id $mjdDay_monthback $mjdDay</b></center>";
    348     }
    349 
    350     //echo "<br><br>";
     345        echo "<center><b>No results found for min_exp_id:$min_exp_id month:$mjdDay_monthback today:$mjdDay</b></center>";
     346    }
    351347
    352348    // Determine the date constraint based on the range
     
    380376 
    381377    // Updated SQL query
    382     $sql = "select * from (SELECT SUBTIME(dateobs, '10:00:00') AS time, AST_R0, AST_D0, AST_RS, AST_DS, AST_T0, posang,
    383                    round(( 367*YEAR(dateobs)- FLOOR((7 * (YEAR(dateobs) + FLOOR((MONTH(dateobs) + 9) / 12))) / 4) + FLOOR(275 * MONTH(dateobs) / 9)
    384                    + DAY(dateobs) + 1721013.5 + (HOUR(dateobs) / 24.0) + (MINUTE(dateobs) / 1440.0) + (SECOND(dateobs) / 86400.0) - 2400000.5), 5) AS MJD,
    385                    filter, comment, round(ra*180/pi(), 5) as RA, round(decl*180/pi(), 5) as DECL, exp_name, alt,
    386                    az, fwhm_major, fwhm_minor, zpt_obs, zpt_stdev, airmass, exp_time,
    387                    rawExp.exp_id, camRun.label, moon_angle, cam_id, BIT_COUNT(astrom_chips) AS working_chips
    388             FROM rawExp
    389             JOIN chipRun USING (exp_id)
    390             JOIN camRun USING (chip_id)
    391             JOIN camProcessedExp USING (cam_id)
    392             WHERE $dateConstraint
    393               AND exp_type = 'OBJECT'
    394               AND camRun.state LIKE 'full'
    395               AND camProcessedExp.fault = 0
    396               AND camProcessedExp.zpt_obs != 0 ORDER BY RAND() limit 10000) as sub order by time;";
    397 
    398     $stmt = $db->query($sql);
    399     $DQarray = $stmt->fetchAll(PDO::FETCH_ASSOC);
    400    
    401     // Ensure $DQarray is not empty
    402     if (empty($DQarray)) {
    403         echo "<center><b> No data for MJD: $mjdDay </b></center>";
    404         return; // Stop execution if no data to encode
    405     }
    406    
    407     // Convert data array to JSON for easier handling in JavaScript
    408     $dataJson = json_encode($DQarray);
    409    
    410     if ($dataJson === false) {
    411         echo "<b>Error encoding JSON:</b> " . json_last_error_msg(); // Display any JSON encoding errors
    412         return; // Stop execution if JSON encoding fails
    413     }
    414    
    415     echo "<script>console.log(" . json_encode($dataJson) . ");</script>"; // Log JSON output to console for debugging
    416 
    417 
    418     echo <<<HTML
    419     <script type="text/javascript">
    420     // Use the encoded JSON directly in JavaScript
    421     const dataArray = JSON.parse('{$dataJson}'); // Directly parse the PHP JSON string
    422 
    423     const nRows = dataArray.length;
    424 
    425     // draw pointing vs mjd
    426     function drawMJDChart() {
    427         var data = new google.visualization.DataTable();
    428             data.addColumn('number', 'MJD');
    429             data.addColumn('number', 'RA_offset (AST_R0)');
    430             data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
    431             data.addColumn({type: 'number', role: 'interval'});
    432             data.addColumn({type: 'number', role: 'interval'});
    433             data.addColumn('number', 'Dec_offset (AST_D0)');
    434             data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
    435             data.addColumn({type: 'number', role: 'interval'});
    436             data.addColumn({type: 'number', role: 'interval'});
    437             data.addColumn('number', '20 TP unit ~5.1"');
    438             data.addColumn('number', '-20 TP unit ~5.1"');
    439 
    440         const mjdValues = dataArray.map(r => parseFloat(r.MJD));
    441         let mjdMin0 = Math.min(...mjdValues);
    442         const mjdMin = Math.floor(mjdMin0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    443         let mjdMax0 = Math.max(...mjdValues);
    444         const mjdMax = Math.ceil(mjdMax0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    445         // Extract the first MJD value from dataArray
    446         const firstMJD = dataArray.length > 0 ? Math.floor(parseFloat(dataArray[0].MJD)) : "N/A";
    447         console.log("First MJD Value:", firstMJD);
    448         const mjdoff = mjdMin;
    449 
    450         const mjdVals = [];
    451         const rows = dataArray.map(row => {
    452             const mjd     = parseFloat(row.MJD) - mjdoff; // MJD shift to first one
    453             mjdVals.push(mjd);  // collect MJD offset values
    454             const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
    455             const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
    456             const ra_sct  = parseFloat(row.AST_RS);  // RA_scatter (AST_RS)
    457             const dec_sct = parseFloat(row.AST_DS);  // DEC_scatter (AST_DS)
    458             const tooltip  = buildTooltip(row);      // Tooltip
    459 
    460             return [
    461               mjd, ra_off, tooltip, ra_off-ra_sct, ra_off+ra_sct, dec_off, tooltip, dec_off-dec_sct, dec_off+dec_sct,
    462               20,   // Dummy value for 20 TP unit
    463               -20  // Dummy value for -20 TP unit
    464             ];
    465         });
    466 
    467         data.addRows(rows);
    468 
    469         // After building rows:
    470         const allVerticalVals = rows.flatMap(r => [
    471           r[3], // ra_off - ra_sct
    472           r[4], // ra_off + ra_sct
    473           r[7], // dec_off - dec_sct
    474           r[8]  // dec_off + dec_sct
    475         ]).filter(v => !isNaN(v)); // âœ
    476  remove NaN values
    477        
    478         // If array is empty after filtering, use safe defaults
    479         const minY = allVerticalVals.length ? Math.min(...allVerticalVals) : 0;
    480         const maxY = allVerticalVals.length ? Math.max(...allVerticalVals) : 0;
    481        
    482         // Clamp values: use ±100 if beyond 100
    483         const yMin = Math.abs(minY) > 150 ? -150 : minY;
    484         const yMax = Math.abs(maxY) > 150 ?  150 : maxY;
    485        
    486         console.log("minY:", minY, yMin, "maxY:", maxY, yMax);
    487 
    488         // Now compute min and max
    489         const mjdMin1 = Math.min(...mjdVals);
    490         const mjdMax1 = Math.max(...mjdVals);
    491 
    492         const defaultSeries = { pointSize: 5, lineWidth: 0 };
    493 
    494         const titleText = `Pointing Offset vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
    495         const options = {
    496             //title: 'Pointing Offset vs. MJD ({$proj})',
    497             title: titleText,
    498             titleTextStyle: {color: 'black', fontSize: 15},
    499             width: '100%',
    500             height: 480,
    501             legend: { position: 'top', alignment: 'center' },
    502             series: {
    503                 0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
    504                 1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
    505                 2: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }, // Line at y = 20
    506                 3: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }  // Line at y = -20
    507             },
    508             intervals: { lineWidth: .5, style: 'sticks' },
    509             interval: {
    510               0: {color: 'blue'},    // interval columns attached to first series
    511               1: {color: 'green'}    // interval columns attached to second series
    512             },
    513             hAxis: {
    514                 title: 'MJD - ' + mjdoff + ' (day)',
    515                 viewWindow: {
    516                    min: 0.,  // small padding
    517                    max: mjdMax1 + 0.005
    518                 },
    519                gridlines: { count: -1 }  // auto gridlines
    520             },
    521             vAxis: {
    522               title: 'Pointing Offset (TP units)',
    523               viewWindow: {
    524                 min: yMin,
    525                 max: yMax
    526               }
    527             },
    528             tooltip: { isHtml: true }, // Render tooltips as HTML
    529             chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
    530             fontSize: 15,
    531         };
    532 
    533         const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_mjd'));
    534         chart.draw(data, options);
    535     }
    536 
    537     // position angle
    538     function drawPOSChart() {
    539         var data = new google.visualization.DataTable();
    540             data.addColumn('number', 'Posang');
    541             data.addColumn('number', 'RA_offset (AST_R0)');
    542             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    543             data.addColumn('number', 'Dec_offset (AST_D0)');
    544             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    545 
    546         const rows = dataArray.map(row => {
    547             const posang  = parseFloat(row.posang);  // Position Angle
    548             const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
    549             const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
    550             const tooltip  = buildTooltip(row);      // Tooltip
    551             return [
    552               posang, ra_off, tooltip, dec_off, tooltip
    553             ];
    554         });
    555 
    556         data.addRows(rows);
    557 
    558         const titleText = `Pointing Offset vs. Position Angle ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
    559         const options = {
    560             title: titleText,
    561             titleTextStyle: {color: 'black', fontSize: 15},
    562             width: '100%',
    563             height: 480,
    564             legend: { position: 'top', alignment: 'center' },
    565             // pointSize: 5, // Point size for scatter plot
    566             // lineWidth: 2,
    567             series: {
    568                 0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
    569                 1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
    570             },
    571             intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
    572             hAxis: {
    573                 title: 'Position Angle (deg)',
    574                 gridlines: {count: -1}
    575             },
    576              vAxis: {
    577                  title: 'Pointing Offset (TP units)',
    578              },
    579             tooltip: { isHtml: true }, // Render tooltips as HTML
    580             chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
    581             fontSize: 15,
    582         };
    583 
    584         const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_pos'));
    585         chart.draw(data, options);
    586     }
    587 
    588     function drawALTChart() {
    589         var data = new google.visualization.DataTable();
    590             data.addColumn('number', 'Altitute');
    591             data.addColumn('number', 'RA_offset (AST_R0)');
    592             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    593             data.addColumn('number', 'Dec_offset (AST_D0)');
    594             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    595 
    596         const rows = dataArray.map(row => {
    597             const alt     = parseFloat(row.alt);     // Altitude
    598             const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
    599             const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
    600             const tooltip  = buildTooltip(row);      // Tooltip
    601             return [
    602               alt, ra_off, tooltip, dec_off, tooltip
    603             ];
    604         });
    605 
    606         data.addRows(rows);
    607 
    608         const titleText = `Pointing Offset vs. Altitude ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
    609         const options = {
    610             title: titleText,
    611             titleTextStyle: {color: 'black', fontSize: 15},
    612             width: '100%',
    613             height: 480,
    614             legend: { position: 'top', alignment: 'center' },
    615             series: {
    616                 0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
    617                 1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
    618             },
    619             intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
    620             hAxis: {
    621                 title: 'Altitude (deg)',
    622                 gridlines: {count: -1}
    623             },
    624             vAxis: {
    625                 title: 'Pointing Offset (TP units)',
    626             },
    627             tooltip: { isHtml: true }, // Render tooltips as HTML
    628             //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
    629             chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
    630             fontSize: 15,
    631         };
    632 
    633         const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_alt'));
    634         chart.draw(data, options);
    635     }
    636 
    637    function drawAZChart() {
    638         var data = new google.visualization.DataTable();
    639             data.addColumn('number', 'Azumith');
    640             data.addColumn('number', 'RA_offset (AST_R0)');
    641             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    642             data.addColumn('number', 'Dec_offset (AST_D0)');
    643             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    644 
    645         const rows = dataArray.map(row => {
    646             const az      = parseFloat(row.az);      // Azumith
    647             const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
    648             const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
    649             const tooltip  = buildTooltip(row);      // Tooltip
    650             return [
    651               az, ra_off, tooltip, dec_off, tooltip
    652             ];
    653         });
    654 
    655         data.addRows(rows);
    656 
    657         const titleText = `Pointing Offset vs. Azumith ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
    658         const options = {
    659             title: titleText,
    660             titleTextStyle: {color: 'black', fontSize: 15},
    661             width: '100%',
    662             height: 480,
    663             legend: { position: 'top', alignment: 'center' },
    664             series: {
    665                 0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
    666                 1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
    667             },
    668             intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
    669             hAxis: {
    670                 title: 'Azumith (deg)',
    671                 gridlines: {count: -1}
    672             },
    673             vAxis: {
    674                 title: 'Pointing Offset (TP units)',
    675             },
    676             tooltip: { isHtml: true }, // Render tooltips as HTML
    677             //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
    678             chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
    679             fontSize: 15,
    680         };
    681 
    682         const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_az'));
    683         chart.draw(data, options);
    684     }
    685 
    686 
    687    function drawScatChart() {
    688         var data = new google.visualization.DataTable();
    689             data.addColumn('number', 'tmp');
    690             data.addColumn('number', 'RA_scat (AST_RS)');
    691             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    692             data.addColumn('number', 'Dec_scat (AST_DS)');
    693             data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    694 
    695         const rows = dataArray.map(row => {
    696             const par  = parseFloat(row.MJD);
    697             const ra_scat  = parseFloat(row.AST_RS);  // RA_scat (AST_RS)
    698             const dec_scat = parseFloat(row.AST_DS);  // DEC_scat (AST_DS)
    699             const tooltip  = buildTooltip(row);       // Tooltip
    700             return [
    701               par, ra_scat, tooltip, dec_scat, tooltip
    702             ];
    703         });
    704 
    705         data.addRows(rows);
    706 
    707         const titleText = `Pointing Offset vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
    708         const options = {
    709             title: titleText,
    710             titleTextStyle: {color: 'black', fontSize: 15},
    711             width: '100%',
    712             height: 480,
    713             legend: { position: 'top', alignment: 'center' },
    714             series: {
    715                 0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
    716                 1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
    717             },
    718             intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
    719             hAxis: {
    720                 title: 'MJD',
    721                 gridlines: {count: -1}
    722             },
    723             vAxis: {
    724                 title: 'Pointing Scatter (TP units)',
    725               viewWindow: {
    726                 min: 0,
    727                // max: 20
    728               }
    729             },
    730             tooltip: { isHtml: true }, // Render tooltips as HTML
    731             //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
    732             chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
    733             fontSize: 15,
    734         };
    735 
    736         const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_scat'));
    737         chart.draw(data, options);
    738     }
    739 
    740     google.charts.setOnLoadCallback(drawMJDChart);
    741     google.charts.setOnLoadCallback(drawPOSChart);
    742     google.charts.setOnLoadCallback(drawALTChart);
    743     google.charts.setOnLoadCallback(drawAZChart);
    744     google.charts.setOnLoadCallback(drawScatChart);
    745 </script>
    746 
    747 <div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
    748     <div id="dq_div_mjd" style="width:1240px;"></div>
    749 </div>
    750 
    751 <div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
    752     <div id="dq_div_scat" style="width:1240px;"></div>
    753 </div>
    754 
    755 <div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
    756     <div id="dq_div_pos" style="width:1240px;"></div>
    757 </div>
    758 
    759 <div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
    760     <div id="dq_div_alt" style="width:1240px;"></div>
    761 </div>
    762 
    763 <div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
    764     <div id="dq_div_az" style="width:1240px;"></div>
    765 </div>
    766 HTML;
    767 
    768 // End timer
    769 $total_time = round(microtime(true) - $start, 3);
    770 echo "<center>Loading plot in $total_time seconds<br></center>";
    771 
    772 }
    773 
    774 ###########################################################################
    775 #
    776 # Get data quality
    777 #
    778 ###########################################################################
    779 function getDataQuality($db, $range = 'week', $proj) {
    780     // Start timer
    781     $start = microtime(true);
    782 
    783     // testing day
    784     $mjdDay  = getMJD();
    785     //$mjdDay = 60950;
    786     $mjdDay_yearback = $mjdDay - 366;
    787     $mjdDay_monthback = $mjdDay - 32;
    788     $min_exp_id = 0;
    789 
    790 
    791     // Determine the reference exp_name based on the selected range
    792     switch ($range) {
    793         case 'year':
    794             $expname = "o" . $mjdDay_yearback . "%";
    795             break;
    796         case 'month':
    797             $expname = "o" . $mjdDay_monthback . "%";
    798             break;
    799         case 'week':
    800             $expname = "o" . ($mjdDay - 7) . "%";
    801             break;
    802         case 'yesterday':
    803             $expname = "o" . ($mjdDay - 1) . "%";
    804             break;
    805         case 'today':
    806             $expname = "o" . $mjdDay . "%";
    807             break;
    808         default:
    809             $expname = "o" . ($mjdDay - 7) . "%"; // Default: week
    810             break;
    811     }
    812 
    813     // --- PDO query for min_exp_id ---
    814     $stmt = $db->prepare("SELECT MIN(exp_id) AS min_exp_id FROM rawExp WHERE exp_name LIKE :expname");
    815     $stmt->execute([':expname' => $expname]);
    816     $row = $stmt->fetch(PDO::FETCH_ASSOC);
    817     if (!empty($row['min_exp_id'])) {
    818         $min_exp_id = $row['min_exp_id'];
    819         echo "<center><b>min_exp_id:$min_exp_id $mjdDay_monthback $mjdDay</b></center>";
    820     } else {
    821         echo "<center><b>No results found for min_exp_id:$min_exp_id $mjdDay_monthback $mjdDay</b></center>";
    822     }
    823 
    824     // Determine the date constraint based on the range
    825     switch ($range) {
    826         case 'year':
    827             $dateConstraint = "rawExp.dateobs >= NOW() - INTERVAL 365 DAY AND rawExp.exp_id >= $min_exp_id";
    828             break;
    829         case 'month':
    830             $dateConstraint = "rawExp.dateobs >= NOW() - INTERVAL 30 DAY AND rawExp.exp_id >= $min_exp_id";
    831             break;
    832         case 'week':
    833             $expnames = array();
    834             for ($i = 0; $i < 7; $i++) {
    835                 $expnames[] = "rawExp.exp_name LIKE 'o" . ($mjdDay - $i) . "%'";
    836             }
    837             $dateConstraint = "(" . implode(" OR ", $expnames) . ") AND rawExp.exp_id >= $min_exp_id";
    838             $qday = $mjdDay - 6; // or something meaningful for week
    839             break;
    840         case 'yesterday':
    841             $dateConstraint = "rawExp.exp_name LIKE 'o" . ($mjdDay - 1) . "%' AND rawExp.exp_id >= $min_exp_id";
    842             $qday = $mjdDay - 1;
    843             break;
    844         case 'today':
    845             $dateConstraint = "rawExp.exp_name LIKE 'o$mjdDay%' AND rawExp.exp_id >= $min_exp_id";
    846             $qday = $mjdDay;
    847             break;
    848         case 'all':
    849             $dateConstraint = "rawExp.exp_id >= 0";
    850             break;
    851         default: // Default to last night
    852             $dateConstraint = "rawExp.exp_name LIKE 'o" . ($mjdDay - 1) . "%' AND rawExp.exp_id >= $min_exp_id";
    853             $qday = $mjdDay - 1;
    854             break;
    855     }
    856 
    857     // Updated SQL query
    858     $sql1 = "select * from (SELECT SUBTIME(dateobs, '10:00:00') AS time, AST_R0, AST_D0, AST_RS, AST_DS, AST_T0, posang,
    859                    round(( 367*YEAR(dateobs)- FLOOR((7 * (YEAR(dateobs) + FLOOR((MONTH(dateobs) + 9) / 12))) / 4) + FLOOR(275 * MONTH(dateobs) / 9)
    860                    + DAY(dateobs) + 1721013.5 + (HOUR(dateobs) / 24.0) + (MINUTE(dateobs) / 1440.0) + (SECOND(dateobs) / 86400.0) - 2400000.5), 5) AS MJD,
    861                    filter, comment, round(ra*180/pi(), 5) as RA, round(decl*180/pi(), 5) as DECL, exp_name, alt,
    862                    az, fwhm_major, fwhm_minor, zpt_obs, zpt_stdev, airmass, exp_time,
    863                    rawExp.exp_id, camRun.label, moon_angle, cam_id, BIT_COUNT(astrom_chips) AS working_chips
    864             FROM rawExp
    865             JOIN chipRun USING (exp_id)
    866             JOIN camRun USING (chip_id)
    867             JOIN camProcessedExp USING (cam_id)
    868             WHERE $dateConstraint
    869               AND exp_type = 'OBJECT'
    870               AND camRun.state LIKE 'full'
    871               AND camProcessedExp.fault = 0
    872               AND camProcessedExp.zpt_obs != 0 ORDER BY RAND() limit 5000) as sub order by time;";
    873378    $sql = " SELECT * FROM (SELECT
    874379    SUBTIME(rawExp.dateobs, '10:00:00') AS time,
     
    901406    cme.zpt_obs,
    902407    cme.zpt_stdev,
     408    cme.path_base AS image_path,
    903409    rawExp.airmass,
    904410    rawExp.exp_time,
     
    907413    camRun.label,
    908414    camRun.cam_id,
    909     BIT_COUNT(astrom_chips) AS g_chips,
    910     SUM(CASE WHEN rim.bg > 0 THEN 1 ELSE 0 END) AS n_raw,
    911     SUM(CASE WHEN chi.bg IS NOT NULL THEN 1 ELSE 0 END) AS n_read,
    912     SUM(CASE WHEN chi.quality > 0 THEN 1 ELSE 0 END) AS n_poor
    913 
    914 FROM camProcessedExp cme
    915 JOIN camRun USING (cam_id)
    916 JOIN chipRun USING (chip_id)
    917 JOIN chipProcessedImfile chi USING (chip_id)
    918 JOIN rawExp ON (rawExp.exp_id = chipRun.exp_id)
    919 JOIN rawImfile rim ON (rim.exp_id = rawExp.exp_id)
    920 
    921 WHERE
    922     $dateConstraint
    923     AND rawExp.exp_type = 'OBJECT'
    924     AND camRun.state = 'full'
    925     AND cme.fault = 0
    926     AND cme.zpt_obs != 0
    927     AND rim.class_id = chi.class_id
    928 
    929 GROUP BY
     415    BIT_COUNT(astrom_chips) AS good_astro,
     416    SUM(chi.bg IS NOT NULL) AS good_chip,
     417    SUM(chi.bg IS NULL)     AS null_bg,
     418    SUM(chi.n_stars > 5)    AS good_phot,
     419    SUM(chi.quality > 0)    AS poor_chip
     420
     421    FROM camProcessedExp cme
     422    JOIN camRun USING (cam_id)
     423    JOIN chipRun USING (chip_id)
     424    JOIN chipProcessedImfile chi USING (chip_id)
     425    JOIN rawExp ON (rawExp.exp_id = chipRun.exp_id)
     426   
     427    WHERE
     428        $dateConstraint
     429        AND rawExp.exp_type = 'OBJECT'
     430        AND camRun.state = 'full'
     431        AND cme.fault = 0
     432        AND cme.zpt_obs != 0
     433   
     434    GROUP BY
     435        rawExp.exp_name,
     436        camRun.label,
     437        cam_id,
     438        rawExp.dateobs,
     439        rawExp.ra,
     440        rawExp.decl,
     441        rawExp.alt,
     442        rawExp.moon_angle,
     443        astrom_chips,
     444        cme.bg,
     445        cme.n_stars
     446   
     447    ORDER BY RAND() limit 5000) as sub order by time;
     448    ";
     449
     450    $stmt = $db->query($sql);
     451    $DQarray = $stmt->fetchAll(PDO::FETCH_ASSOC);
     452   
     453    // Ensure $DQarray is not empty
     454    if (empty($DQarray)) {
     455        echo "<center><b> No data for MJD: $mjdDay </b></center>";
     456        return; // Stop execution if no data to encode
     457    }
     458   
     459    // Convert data array to JSON for easier handling in JavaScript
     460    $dataJson = json_encode($DQarray);
     461   
     462    if ($dataJson === false) {
     463        echo "<b>Error encoding JSON:</b> " . json_last_error_msg(); // Display any JSON encoding errors
     464        return; // Stop execution if JSON encoding fails
     465    }
     466   
     467    echo "<script>console.log(" . json_encode($dataJson) . ");</script>"; // Log JSON output to console for debugging
     468
     469
     470    echo <<<HTML
     471    <script type="text/javascript">
     472    // Use the encoded JSON directly in JavaScript
     473    const dataArray = JSON.parse('{$dataJson}'); // Directly parse the PHP JSON string
     474
     475    const nRows = dataArray.length;
     476
     477    // draw pointing vs mjd
     478    function drawMJDChart() {
     479        var data = new google.visualization.DataTable();
     480            data.addColumn('number', 'MJD');
     481            data.addColumn('number', 'RA_offset (AST_R0)');
     482            data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
     483            data.addColumn({type: 'number', role: 'interval'});
     484            data.addColumn({type: 'number', role: 'interval'});
     485            data.addColumn('number', 'Dec_offset (AST_D0)');
     486            data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
     487            data.addColumn({type: 'number', role: 'interval'});
     488            data.addColumn({type: 'number', role: 'interval'});
     489            data.addColumn('number', '20 TP unit ~5.1"');
     490            data.addColumn('number', '-20 TP unit ~5.1"');
     491
     492        const mjdoff = $mjdDay;
     493        const rows = dataArray.map(row => {
     494            const mjd     = parseFloat(row.MJD) - mjdoff; // MJD shift to first one
     495            const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
     496            const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
     497            const ra_sct  = parseFloat(row.AST_RS);  // RA_scatter (AST_RS)
     498            const dec_sct = parseFloat(row.AST_DS);  // DEC_scatter (AST_DS)
     499            const tooltip  = buildTooltip(row);      // Tooltip
     500
     501            return [
     502              mjd, ra_off, tooltip, ra_off-ra_sct, ra_off+ra_sct, dec_off, tooltip, dec_off-dec_sct, dec_off+dec_sct,
     503              20,   // Dummy value for 20 TP unit
     504              -20  // Dummy value for -20 TP unit
     505            ];
     506        });
     507
     508        data.addRows(rows);
     509
     510        // After building rows:
     511        const allVerticalVals = rows.flatMap(r => [
     512          r[3], // ra_off - ra_sct
     513          r[4], // ra_off + ra_sct
     514          r[7], // dec_off - dec_sct
     515          r[8]  // dec_off + dec_sct
     516        ]).filter(v => !isNaN(v)); // âœ
     517 remove NaN values
     518       
     519        // If array is empty after filtering, use safe defaults
     520        const minY = allVerticalVals.length ? Math.min(...allVerticalVals) : 0;
     521        const maxY = allVerticalVals.length ? Math.max(...allVerticalVals) : 0;
     522       
     523        // Clamp values: use ±100 if beyond 100
     524        const yMin = Math.abs(minY) > 150 ? -150 : minY;
     525        const yMax = Math.abs(maxY) > 150 ?  150 : maxY;
     526       
     527        console.log("minY:", minY, yMin, "maxY:", maxY, yMax);
     528
     529        const defaultSeries = { pointSize: 5, lineWidth: 0 };
     530
     531        const titleText = `Pointing Offset vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
     532        const options = {
     533            //title: 'Pointing Offset vs. MJD ({$proj})',
     534            title: titleText,
     535            titleTextStyle: {color: 'black', fontSize: 15},
     536            width: '100%',
     537            height: 480,
     538            legend: { position: 'top', alignment: 'center' },
     539            series: {
     540                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
     541                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
     542                2: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }, // Line at y = 20
     543                3: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }  // Line at y = -20
     544            },
     545            intervals: { lineWidth: .5, style: 'sticks' },
     546            interval: {
     547              0: {color: 'blue'},    // interval columns attached to first series
     548              1: {color: 'green'}    // interval columns attached to second series
     549            },
     550            hAxis: {
     551                title: 'MJD - ' + mjdoff + ' (today)',
     552               gridlines: { count: -1 }  // auto gridlines
     553            },
     554            vAxis: {
     555              title: 'Pointing Offset (TP units)',
     556              viewWindow: {
     557                min: yMin,
     558                max: yMax
     559              }
     560            },
     561            tooltip: { isHtml: true }, // Render tooltips as HTML
     562              explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
     563            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
     564            fontSize: 15,
     565        };
     566
     567        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_mjd'));
     568        chart.draw(data, options);
     569    }
     570
     571    // position angle
     572    function drawPOSChart() {
     573        var data = new google.visualization.DataTable();
     574            data.addColumn('number', 'Posang');
     575            data.addColumn('number', 'RA_offset (AST_R0)');
     576            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     577            data.addColumn('number', 'Dec_offset (AST_D0)');
     578            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     579
     580        const rows = dataArray.map(row => {
     581            const posang  = parseFloat(row.posang);  // Position Angle
     582            const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
     583            const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
     584            const tooltip  = buildTooltip(row);      // Tooltip
     585            return [
     586              posang, ra_off, tooltip, dec_off, tooltip
     587            ];
     588        });
     589
     590        data.addRows(rows);
     591
     592        const titleText = `Pointing Offset vs. Position Angle ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
     593        const options = {
     594            title: titleText,
     595            titleTextStyle: {color: 'black', fontSize: 15},
     596            width: '100%',
     597            height: 480,
     598            legend: { position: 'top', alignment: 'center' },
     599            // pointSize: 5, // Point size for scatter plot
     600            // lineWidth: 2,
     601            series: {
     602                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
     603                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
     604            },
     605            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
     606            hAxis: {
     607                title: 'Position Angle (deg)',
     608                gridlines: {count: -1}
     609            },
     610             vAxis: {
     611                 title: 'Pointing Offset (TP units)',
     612             },
     613            tooltip: { isHtml: true }, // Render tooltips as HTML
     614              explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
     615            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
     616            fontSize: 15,
     617        };
     618
     619        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_pos'));
     620        chart.draw(data, options);
     621    }
     622
     623    function drawALTChart() {
     624        var data = new google.visualization.DataTable();
     625            data.addColumn('number', 'Altitute');
     626            data.addColumn('number', 'RA_offset (AST_R0)');
     627            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     628            data.addColumn('number', 'Dec_offset (AST_D0)');
     629            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     630
     631        const rows = dataArray.map(row => {
     632            const alt     = parseFloat(row.alt);     // Altitude
     633            const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
     634            const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
     635            const tooltip  = buildTooltip(row);      // Tooltip
     636            return [
     637              alt, ra_off, tooltip, dec_off, tooltip
     638            ];
     639        });
     640
     641        data.addRows(rows);
     642
     643        const titleText = `Pointing Offset vs. Altitude ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
     644        const options = {
     645            title: titleText,
     646            titleTextStyle: {color: 'black', fontSize: 15},
     647            width: '100%',
     648            height: 480,
     649            legend: { position: 'top', alignment: 'center' },
     650            series: {
     651                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
     652                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
     653            },
     654            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
     655            hAxis: {
     656                title: 'Altitude (deg)',
     657                gridlines: {count: -1}
     658            },
     659            vAxis: {
     660                title: 'Pointing Offset (TP units)',
     661            },
     662            tooltip: { isHtml: true }, // Render tooltips as HTML
     663              explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
     664            //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
     665            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
     666            fontSize: 15,
     667        };
     668
     669        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_alt'));
     670        chart.draw(data, options);
     671    }
     672
     673   function drawAZChart() {
     674        var data = new google.visualization.DataTable();
     675            data.addColumn('number', 'Azumith');
     676            data.addColumn('number', 'RA_offset (AST_R0)');
     677            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     678            data.addColumn('number', 'Dec_offset (AST_D0)');
     679            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     680
     681        const rows = dataArray.map(row => {
     682            const az      = parseFloat(row.az);      // Azumith
     683            const ra_off  = parseFloat(row.AST_R0);  // RA_offset (AST_R0)
     684            const dec_off = parseFloat(row.AST_D0);  // DEC_offset (AST_D0)
     685            const tooltip  = buildTooltip(row);      // Tooltip
     686            return [
     687              az, ra_off, tooltip, dec_off, tooltip
     688            ];
     689        });
     690
     691        data.addRows(rows);
     692
     693        const titleText = `Pointing Offset vs. Azumith ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
     694        const options = {
     695            title: titleText,
     696            titleTextStyle: {color: 'black', fontSize: 15},
     697            width: '100%',
     698            height: 480,
     699            legend: { position: 'top', alignment: 'center' },
     700            series: {
     701                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
     702                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
     703            },
     704            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
     705            hAxis: {
     706                title: 'Azumith (deg)',
     707                gridlines: {count: -1}
     708            },
     709            vAxis: {
     710                title: 'Pointing Offset (TP units)',
     711            },
     712            tooltip: { isHtml: true }, // Render tooltips as HTML
     713              explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
     714            //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
     715            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
     716            fontSize: 15,
     717        };
     718
     719        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_az'));
     720        chart.draw(data, options);
     721    }
     722
     723
     724   function drawScatChart() {
     725        var data = new google.visualization.DataTable();
     726            data.addColumn('number', 'MJD');
     727            data.addColumn('number', 'RA_scat (AST_RS)');
     728            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     729            data.addColumn('number', 'Dec_scat (AST_DS)');
     730            data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     731
     732        const mjdoff = $mjdDay;
     733        const rows = dataArray.map(row => {
     734            const mjd      = parseFloat(row.MJD) - mjdoff; // MJD shift to first one
     735            const ra_scat  = parseFloat(row.AST_RS);  // RA_scat (AST_RS)
     736            const dec_scat = parseFloat(row.AST_DS);  // DEC_scat (AST_DS)
     737            const tooltip  = buildTooltip(row);       // Tooltip
     738            return [
     739              mjd, ra_scat, tooltip, dec_scat, tooltip
     740            ];
     741        });
     742
     743        data.addRows(rows);
     744
     745        const titleText = `Pointing Offset vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 10000 ? " (sampled)" : ""}`;
     746        const options = {
     747            title: titleText,
     748            titleTextStyle: {color: 'black', fontSize: 15},
     749            width: '100%',
     750            height: 280,
     751            legend: { position: 'top', alignment: 'center' },
     752            series: {
     753                0: { color: '#0000ff', pointSize: 3, lineWidth: 0 }, // RA_offset series
     754                1: { color: '#33a532', pointSize: 3, lineWidth: 0 }, // Dec_offset series
     755            },
     756            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
     757            hAxis: {
     758                title: 'MJD - ' + mjdoff + ' (today)',
     759                gridlines: {count: -1}
     760            },
     761            vAxis: {
     762                title: 'Scatter (TP units)',
     763              viewWindow: {
     764                min: 0,
     765               // max: 20
     766              }
     767            },
     768            tooltip: { isHtml: true }, // Render tooltips as HTML
     769              explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
     770            //chartArea: {left: 80, top: 50, right: 20, bottom: 50},
     771            chartArea: {left: '7%', top: 60, right: '4%', bottom: 50}, // Adjust left and right
     772            fontSize: 15,
     773        };
     774
     775        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_scat'));
     776        chart.draw(data, options);
     777    }
     778
     779    google.charts.setOnLoadCallback(drawMJDChart);
     780    google.charts.setOnLoadCallback(drawPOSChart);
     781    google.charts.setOnLoadCallback(drawALTChart);
     782    google.charts.setOnLoadCallback(drawAZChart);
     783    google.charts.setOnLoadCallback(drawScatChart);
     784</script>
     785
     786<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
     787    <div id="dq_div_mjd" style="width:1240px;"></div>
     788</div>
     789
     790<div class="chartWithOverlay" style="position: relative; width: 1240px; height:300px;">
     791    <div id="dq_div_scat" style="width:1240px;"></div>
     792</div>
     793
     794<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
     795    <div id="dq_div_pos" style="width:1240px;"></div>
     796</div>
     797
     798<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
     799    <div id="dq_div_alt" style="width:1240px;"></div>
     800</div>
     801
     802<div class="chartWithOverlay" style="position: relative; width: 1240px; height:500px;">
     803    <div id="dq_div_az" style="width:1240px;"></div>
     804</div>
     805HTML;
     806
     807// End timer
     808$total_time = round(microtime(true) - $start, 3);
     809echo "<center>Loading plot in $total_time seconds<br></center>";
     810
     811}
     812
     813###########################################################################
     814#
     815# Get data quality
     816#
     817###########################################################################
     818function getDataQuality($db, $range = 'week', $proj) {
     819    // Start timer
     820    $start = microtime(true);
     821    // mjd today
     822    $mjdDay  = getMJD();
     823    // testing day
     824    //$mjdDay = 61104;
     825    $mjdDay_yearback = $mjdDay - 366;
     826    $mjdDay_monthback = $mjdDay - 30;
     827    $min_exp_id = 0;
     828
     829
     830    // Determine the reference exp_name based on the selected range
     831    switch ($range) {
     832        case 'year':
     833            $expname = "o" . $mjdDay_yearback . "%";
     834            break;
     835        case 'month':
     836            $expname = "o" . $mjdDay_monthback . "%";
     837            break;
     838        case 'week':
     839            $expname = "o" . ($mjdDay - 7) . "%";
     840            break;
     841        case 'yesterday':
     842            $expname = "o" . ($mjdDay - 1) . "%";
     843            break;
     844        case 'today':
     845            $expname = "o" . $mjdDay . "%";
     846            break;
     847        default:
     848            $expname = "o" . ($mjdDay - 7) . "%"; // Default: week
     849            break;
     850    }
     851
     852    // --- PDO query for min_exp_id ---
     853    $stmt = $db->prepare("SELECT MIN(exp_id) AS min_exp_id FROM rawExp WHERE exp_name LIKE :expname");
     854    $stmt->execute([':expname' => $expname]);
     855    $row = $stmt->fetch(PDO::FETCH_ASSOC);
     856    if (!empty($row['min_exp_id'])) {
     857        $min_exp_id = $row['min_exp_id'];
     858        echo "<center><b>min_exp_id $min_exp_id in $range $expname - $mjdDay (today)</b></center>";
     859    } else {
     860        echo "<center><b>No min_exp_id $min_exp_id in $range $expname - $mjdDay (today)</b></center>";
     861    }
     862
     863    // Determine the date constraint based on the range
     864    switch ($range) {
     865        case 'year':
     866            $dateConstraint = "rawExp.dateobs >= NOW() - INTERVAL 365 DAY AND rawExp.exp_id >= $min_exp_id";
     867            break;
     868        case 'month':
     869            $dateConstraint = "rawExp.dateobs >= NOW() - INTERVAL 30 DAY AND rawExp.exp_id >= $min_exp_id";
     870            break;
     871        case 'week':
     872            $expnames = array();
     873            for ($i = 0; $i < 7; $i++) {
     874                $expnames[] = "rawExp.exp_name LIKE 'o" . ($mjdDay - $i) . "%'";
     875            }
     876            $dateConstraint = "(" . implode(" OR ", $expnames) . ") AND rawExp.exp_id >= $min_exp_id";
     877            $qday = $mjdDay - 6; // or something meaningful for week
     878            break;
     879        case 'yesterday':
     880            $dateConstraint = "rawExp.exp_name LIKE 'o" . ($mjdDay - 1) . "%' AND rawExp.exp_id >= $min_exp_id";
     881            $qday = $mjdDay - 1;
     882            break;
     883        case 'today':
     884            $dateConstraint = "rawExp.exp_name LIKE 'o$mjdDay%' AND rawExp.exp_id >= $min_exp_id";
     885            $qday = $mjdDay;
     886            break;
     887        case 'all':
     888            $dateConstraint = "rawExp.exp_id >= 0";
     889            break;
     890        default: // Default to last night
     891            $dateConstraint = "rawExp.exp_name LIKE 'o" . ($mjdDay - 1) . "%' AND rawExp.exp_id >= $min_exp_id";
     892            $qday = $mjdDay - 1;
     893            break;
     894    }
     895
     896    // Updated SQL query
     897    $sql = " SELECT * FROM (SELECT
     898    SUBTIME(rawExp.dateobs, '10:00:00') AS time,
     899    cme.AST_R0,
     900    cme.AST_D0,
     901    cme.AST_RS,
     902    cme.AST_DS, 
     903    cme.AST_T0,
     904    rawExp.posang,
     905    ROUND(
     906        (367*YEAR(rawExp.dateobs)
     907        - FLOOR((7*(YEAR(rawExp.dateobs)+FLOOR((MONTH(rawExp.dateobs)+9)/12)))/4)
     908        + FLOOR(275*MONTH(rawExp.dateobs)/9)
     909        + DAY(rawExp.dateobs)
     910        + 1721013.5
     911        + (HOUR(rawExp.dateobs)/24.0)
     912        + (MINUTE(rawExp.dateobs)/1440.0)
     913        + (SECOND(rawExp.dateobs)/86400.0)
     914        - 2400000.5),5
     915    ) AS MJD,
     916    rawExp.filter,
     917    rawExp.comment,
     918    ROUND(rawExp.ra*180/PI(),5) AS RA,
     919    ROUND(rawExp.decl*180/PI(),5) AS DECL,
    930920    rawExp.exp_name,
     921    rawExp.alt,
     922    rawExp.az,
     923    cme.fwhm_major,
     924    cme.fwhm_minor,
     925    cme.zpt_obs,
     926    cme.zpt_stdev,
     927    cme.path_base AS image_path,
     928    rawExp.airmass,
     929    rawExp.exp_time,
     930    rawExp.exp_id,
     931    rawExp.moon_angle,
    931932    camRun.label,
    932     cam_id,
    933     rawExp.dateobs,
    934     rawExp.ra,
    935     rawExp.decl,
    936     rawExp.alt,
    937     rawExp.moon_angle,
    938     astrom_chips,
    939     cme.bg,
    940     cme.n_stars
    941 
    942 ORDER BY RAND() limit 5000) as sub order by time;
    943 ";
     933    camRun.cam_id,
     934    BIT_COUNT(astrom_chips) AS good_astro,
     935    SUM(chi.bg IS NOT NULL) AS good_chip,
     936    SUM(chi.bg IS NULL)     AS null_bg,
     937    SUM(chi.n_stars > 5)    AS good_phot,
     938    SUM(chi.quality > 0)    AS poor_chip
     939
     940    FROM camProcessedExp cme
     941    JOIN camRun USING (cam_id)
     942    JOIN chipRun USING (chip_id)
     943    JOIN chipProcessedImfile chi USING (chip_id)
     944    JOIN rawExp ON (rawExp.exp_id = chipRun.exp_id)
     945   
     946    WHERE
     947        $dateConstraint
     948        AND rawExp.exp_type = 'OBJECT'
     949        AND camRun.state = 'full'
     950        AND cme.fault = 0
     951   
     952    GROUP BY
     953        rawExp.exp_name,
     954        camRun.label,
     955        cam_id,
     956        rawExp.dateobs,
     957        rawExp.ra,
     958        rawExp.decl,
     959        rawExp.alt,
     960        rawExp.moon_angle,
     961        astrom_chips,
     962        cme.bg,
     963        cme.n_stars
     964   
     965    ORDER BY RAND() limit 5000) as sub order by time;
     966    ";
    944967
    945968//echo "<center>$sql</center><br>";
    946 //echo "<center>$sql1</center>";
    947969    $stmt = $db->query($sql);
    948970    $DQarray = $stmt->fetchAll(PDO::FETCH_ASSOC);
     
    9851007        var data = new google.visualization.DataTable();
    9861008        data.addColumn('number', 'MJD');
    987         data.addColumn('number', 'Number of raw Chips');
     1009        data.addColumn('number', 'good phot (nstar>5)');
    9881010        data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    989 //        data.addColumn('number', 'Number of Good Chips');
    990 //        data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    991 
    992         const mjdValues = dataArray.map(r => parseFloat(r.MJD));
    993         let mjdMin0 = Math.min(...mjdValues);
    994         const mjdMin = Math.floor(mjdMin0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    995         let mjdMax0 = Math.max(...mjdValues);
    996         const mjdMax = Math.ceil(mjdMax0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    997         // Extract the first MJD value from dataArray
    998         const firstMJD = dataArray.length > 0 ? Math.floor(parseFloat(dataArray[0].MJD)) : "N/A";
    999         const mjdoff = mjdMin;
    1000         // output at console
    1001         // console.log("First MJD Value:", firstMJD);
    1002 
     1011        data.addColumn('number', 'good astro');
     1012        data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     1013        data.addColumn('number', 'null bg');
     1014        data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     1015        data.addColumn('number', 'poor (q>0)');
     1016        data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     1017
     1018        const mjdoff = $mjdDay;
    10031019        // build data rows
    1004         const mjdVals = [];
    10051020        const rows = dataArray.map(row => {
    10061021            const mjd    = parseFloat(row.MJD) - mjdoff;
    1007             mjdVals.push(mjd);  // collect MJD offset values
    1008 
    1009             const n_raw   = parseFloat(row.n_raw)+1;
    1010             const n_chips = parseFloat(row.g_chips);
    1011             const f_good  = n_chips / n_raw;
     1022            const null_bg    = parseFloat(row.null_bg);
     1023            const good_phot  = parseFloat(row.good_phot);
     1024            const good_astro = parseFloat(row.good_astro);
     1025            const poor_chip  = parseFloat(row.poor_chip);
    10121026            const tooltip = buildTooltip(row);
    10131027
    10141028            return[
    1015                 mjd, f_good, tooltip,
     1029                mjd, good_phot, tooltip, good_astro, tooltip, null_bg, tooltip, poor_chip, tooltip,
    10161030            ];
    10171031        });
     
    10191033        data.addRows(rows);
    10201034
    1021         // Now compute min and max
    1022         const mjdMin1 = Math.min(...mjdVals);
    1023         const mjdMax1 = Math.max(...mjdVals);
    1024 
    1025         const titleText = `N Chips vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 5000 ? " (sampled)" : ""}`;
     1035        const titleText = `Chips ratio vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 5000 ? " (sampled)" : ""}`;
     1036
     1037        const options = {
     1038               title: titleText,
     1039               titleTextStyle: {color: 'black', fontSize: 14, bold: true},
     1040               width:  '100%',
     1041               height: Math.min(window.innerHeight * 0.6, 430), // This gives a nice result on smaller screens.
     1042               legend: { position: 'top', alignment: 'center' },
     1043               series: {
     1044                   //0: { color: '#ffe000', pointShape: 'star',  pointSize:  10, lineWidth: 0},
     1045                   0: { color: '#0000ff', pointShape: 'square',  pointSize:  8, lineWidth: 0},
     1046                   1: { color: '#33a532', pointShape: 'triangle',pointSize:  5, lineWidth: 0},
     1047                   2: { color: '#ff0000', pointShape: 'star',  pointSize:  8, lineWidth: 0},
     1048                   3: { color: '#808080', pointShape: 'triangle',pointSize:  5, lineWidth: 0},
     1049               },
     1050              intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
     1051              hAxis: {
     1052                title: 'MJD - ' + mjdoff + ' (today)',
     1053                gridlines: { count: -1 }  // auto gridlines
     1054              },
     1055              vAxis: {
     1056                  title: 'number of chips',
     1057              },
     1058              tooltip: { isHtml: true }, // Render tooltips as HTML
     1059              explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
     1060              chartArea: {left: '9%', top: '10%', right: '3%', bottom: 50}, // Adjust left and right
     1061              fontSize: 14,
     1062         };
     1063
     1064      const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_chips'));
     1065        chart.draw(data, options);
     1066    }
     1067
     1068    // draw FWHM vs MJD
     1069    function drawFWHMChart() {
     1070
     1071        // data header
     1072        var data = new google.visualization.DataTable();
     1073        data.addColumn('number', 'MJD');
     1074        data.addColumn('number', 'FWHM_maj');
     1075        data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     1076        data.addColumn('number', 'FWHM_min');
     1077        data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
     1078        data.addColumn('number', '1"');
     1079        data.addColumn('number', '3"');
     1080
     1081        // build data rows
     1082        const mjdoff = $mjdDay;
     1083        const rows = dataArray.map(row => {
     1084            const mjd    = parseFloat(row.MJD) - mjdoff;
     1085            const fwhm_maj = parseFloat(row.fwhm_major);
     1086            const fwhm_min = parseFloat(row.fwhm_minor);
     1087            const tooltip  = buildTooltip(row);
     1088            return[
     1089                mjd, fwhm_maj, tooltip, fwhm_min, tooltip, 4, 12,
     1090            ];
     1091        });
     1092
     1093        data.addRows(rows);
     1094
     1095        const titleText = `FWHM vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 5000 ? " (sampled)" : ""}`;
    10261096
    10271097        const options = {
     
    10391109            intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
    10401110            hAxis: {
    1041                 title: 'MJD - ' + mjdoff + ' (day)',
    1042                 viewWindow: {
    1043                    min: 0.,  // small padding
    1044                    max: mjdMax1 + 0.005
    1045                 },
    1046                gridlines: { count: -1 }  // auto gridlines
    1047             },
    1048             vAxis: {
    1049                 title: 'Good chips (number)',
    1050             //    viewWindow: {
    1051             //       max: 65,
    1052             //       min: 0
    1053             //    },
    1054             },
    1055             tooltip: { isHtml: true }, // Render tooltips as HTML
    1056             chartArea: {left: '9%', top: '10%', right: '3%', bottom: 50}, // Adjust left and right
    1057             fontSize: 14,
    1058         };
    1059 
    1060         const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_chips'));
    1061         chart.draw(data, options);
    1062     }
    1063 
    1064     // draw FWHM vs MJD
    1065     function drawFWHMChart() {
    1066 
    1067         // data header
    1068         var data = new google.visualization.DataTable();
    1069         data.addColumn('number', 'MJD');
    1070         data.addColumn('number', 'FWHM_maj');
    1071         data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    1072         data.addColumn('number', 'FWHM_min');
    1073         data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}});
    1074         data.addColumn('number', '1"');
    1075         data.addColumn('number', '3"');
    1076 
    1077         const mjdValues = dataArray.map(r => parseFloat(r.MJD));
    1078         let mjdMin0 = Math.min(...mjdValues);
    1079         const mjdMin = Math.floor(mjdMin0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    1080         let mjdMax0 = Math.max(...mjdValues);
    1081         const mjdMax = Math.ceil(mjdMax0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    1082         // Extract the first MJD value from dataArray
    1083         const firstMJD = dataArray.length > 0 ? Math.floor(parseFloat(dataArray[0].MJD)) : "N/A";
    1084         const mjdoff = mjdMin;
    1085         // output at console
    1086         // console.log("First MJD Value:", firstMJD);
    1087 
    1088         // build data rows
    1089         const mjdVals = [];
    1090         const rows = dataArray.map(row => {
    1091             const mjd    = parseFloat(row.MJD) - mjdoff;
    1092             mjdVals.push(mjd);  // collect MJD offset values
    1093 
    1094             const fwhm_maj = parseFloat(row.fwhm_major);
    1095             const fwhm_min = parseFloat(row.fwhm_minor);
    1096             const tooltip  = buildTooltip(row);
    1097 
    1098             return[
    1099                 mjd, fwhm_maj, tooltip, fwhm_min, tooltip, 4, 12,
    1100             ];
    1101         });
    1102 
    1103         data.addRows(rows);
    1104 
    1105         // Now compute min and max
    1106         const mjdMin1 = Math.min(...mjdVals);
    1107         const mjdMax1 = Math.max(...mjdVals);
    1108 
    1109         const titleText = `FWHM vs. MJD ({$proj}) — \${nRows} rows\${dataArray.length >= 5000 ? " (sampled)" : ""}`;
    1110 
    1111         const options = {
    1112             title: titleText,
    1113             titleTextStyle: {color: 'black', fontSize: 14, bold: true},
    1114             width:  '100%',
    1115             height: Math.min(window.innerHeight * 0.6, 430), // This gives a nice result on smaller screens.
    1116             legend: { position: 'top', alignment: 'center' },
    1117             series: {
    1118                 0: { color: '#0000ff', pointSize: 3, lineWidth: 0. },
    1119                 1: { color: '#33a532', pointSize: 3, lineWidth: 0. },
    1120                 2: { color: 'red', lineWidth: 2, pointSize: 0 },
    1121                 3: { color: 'red', lineWidth: 2, lineDashStyle: [8, 4], pointSize: 0 }
    1122             },
    1123             intervals: { color: 'red', lineWidth: 2, style: 'sticks' },
    1124             hAxis: {
    1125                 title: 'MJD - ' + mjdoff + ' (day)',
    1126                 viewWindow: {
    1127                    min: 0.,  // small padding
    1128                    max: mjdMax1 + 0.005
    1129                 },
    1130                gridlines: { count: -1 }  // auto gridlines
     1111                title: 'MJD - ' + mjdoff + ' (today)',
     1112                gridlines: { count: -1 }  // auto gridlines
    11311113            },
    11321114            vAxis: {
     
    11341116            },
    11351117            tooltip: { isHtml: true }, // Render tooltips as HTML
     1118            explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
    11361119            chartArea: {left: '9%', top: '10%', right: '3%', bottom: 50}, // Adjust left and right
    11371120            fontSize: 14,
     
    11681151        const filterCounts = Object.fromEntries(filters.map(f => [f.key, 0]));
    11691152   
    1170         const mjdValues = dataArray.map(r => parseFloat(r.MJD));
    1171         const mjdMin0 = Math.min(...mjdValues);
    1172         const mjdMax0 = Math.max(...mjdValues);
    1173         const mjdMin = Math.floor(mjdMin0 * 10) / 10;
    1174         const mjdMax = Math.ceil(mjdMax0 * 10) / 10;
    1175         const mjdoff = mjdMin;
    1176    
    1177         const mjdVals = [];
    1178    
    11791153        // build rows
     1154        const mjdoff = $mjdDay;
    11801155        const rows = dataArray.map(row => {
    11811156            const mjd = parseFloat(row.MJD) - mjdoff;
    1182             mjdVals.push(mjd);
    1183    
    11841157            const filter = row.filter[0];
    11851158            const zpt_obs = parseFloat(row.zpt_obs);
     
    12241197        data.addRows(rows);
    12251198   
    1226         const mjdMin1 = Math.min(...mjdVals);
    1227         const mjdMax1 = Math.max(...mjdVals);
    12281199        const defaultSeries = { pointSize: 6, lineWidth: 0 };
    12291200   
     
    12441215            intervals: { color: 'red', lineWidth: .0, style: 'sticks' },
    12451216            hAxis: {
    1246                 title: 'MJD - ' + mjdoff + ' (day)',
    1247                 viewWindow: { min: 0, max: mjdMax1 + 0.005 },
     1217                title: 'MJD - ' + mjdoff + ' (today)',
    12481218                gridlines: { count: -1 }
    12491219            },
     
    12531223            },
    12541224            tooltip: { isHtml: true },
     1225            explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
    12551226            chartArea: { left: '9%', top: '10%', right: '3%', bottom: 50 },
    12561227            fontSize: 14,
    12571228        };
    1258         // options.series[1]  = { color: 'black', lineDashStyle: [2, 3], lineWidth: 2, pointSize: 0 };
    1259         // options.series[3]  = { color: 'black', lineDashStyle: [2, 3], lineWidth: 2, pointSize: 0 };
    1260         // options.series[5]  = { color: 'black', lineDashStyle: [2, 3], lineWidth: 2, pointSize: 0 };
    1261         // options.series[7]  = { color: 'black', lineDashStyle: [2, 3], lineWidth: 2, pointSize: 0 };
    1262         // options.series[9]  = { color: 'black', lineDashStyle: [2, 3], lineWidth: 2, pointSize: 0 };
    1263         // options.series[11] = { color: 'black', lineDashStyle: [2, 3], lineWidth: 2, pointSize: 0 };
    12641229   
    12651230        const chart = new google.visualization.ScatterChart(document.getElementById('dq_div_zpt'));
     
    12691234    // draw zoomed zerpoint vs mjd
    12701235    function drawZOOMZPTChart() {
    1271         const mjdValues = dataArray.map(r => parseFloat(r.MJD));
    1272         let mjdMin0 = Math.min(...mjdValues);
    1273         const mjdMin = Math.floor(mjdMin0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    1274         let mjdMax0 = Math.max(...mjdValues);
    1275         const mjdMax = Math.ceil(mjdMax0 * 10) / 10; // 1 decimal place or floor/ceil depending on your needs
    1276         // Extract the first MJD value from dataArray
    1277         const firstMJD = dataArray.length > 0 ? Math.floor(parseFloat(dataArray[0].MJD)) : "N/A";
    1278         const mjdoff = mjdMin;
    1279         // output at console
    1280         console.log("First MJD Value:", firstMJD);
    1281 
    12821236        // Compute median zpt_obs per filter
    12831237        function median(arr) {
     
    13131267              // ref?
    13141268              gzp0 = 24.563; rzp0 = 24.750; izp0 = 24.611; zzp0 = 24.240; yzp0 = 23.320; wzp0 = 26.000;
    1315               //
    1316               //gzp0 = 24.563; rzp0 = 24.750; izp0 = 24.611; zzp0 = 24.240; yzp0 = 23.320; wzp0 = 26.000;
    13171269              break;
    13181270            case 'gpc2':
     
    13421294        };
    13431295
    1344         const mjdVals = [];
    13451296        let allZps = [];
     1297        const mjdoff = $mjdDay;
    13461298        const rows = dataArray.map(row => {
    13471299            const mjd = parseFloat(row.MJD) - mjdoff;
     
    13661318                rowData.push( zp, tooltip, zp !== null ? zp - zpt_stdev : null, zp !== null ? zp + zpt_stdev : null);
    13671319            });
    1368 
    1369             // collect MJD offset values
    1370             mjdVals.push(mjd);
    13711320
    13721321            // collect valid zp values
     
    14451394
    14461395        // plot options
    1447         const mjdMin1 = Math.min(...mjdVals);
    1448         const mjdMax1 = Math.max(...mjdVals);
    14491396        const defaultSeries = { pointSize: 6, lineWidth: 0 };
    14501397
     
    14561403            width: '100%',
    14571404            height: Math.min(window.innerHeight * 0.6, 430), // This gives a nice result on smaller screens.
    1458             //legend: { position: 'top', alignment: 'center', maxLines: 3, textStyle: {fontSize: 12} },
    1459             legend: { position: 'none', alignment: 'center', maxLines: 3 },
     1405            legend: { position: 'top', alignment: 'center', maxLines: 3, textStyle: {fontSize: 12} },
     1406            //legend: { position: 'none', alignment: 'center', maxLines: 3 },
    14601407            series: {
    14611408                0: { ...defaultSeries, color: '#00f000', pointShape: 'circle',   },  // 'g' filter
     
    14681415            intervals: { color: 'red', lineWidth: .0, style: 'sticks' },
    14691416            hAxis: {
    1470                 title: 'MJD - ' + mjdoff + ' (day)',
    1471                 viewWindow: {
    1472                    min: 0,  // small padding
    1473                    max: mjdMax1 + 0.005
    1474                 },
     1417                title: 'MJD - ' + mjdoff + ' (today)',
    14751418                gridlines: { count: -1 },
    14761419                minorGridlines: { count: 1 }
     
    14841427            },
    14851428            tooltip: { isHtml: true},
     1429            explorer: { actions: ['dragToZoom', 'rightClickToReset'], axis: 'horizontal', keepInBounds: true, maxZoomIn: .01}, //  Zoom
    14861430            chartArea: { left: '9%', top: '12%', right: '3%', bottom: 50 },
    14871431            fontSize: 14,
     
    15011445<div class="chartWithOverlay" style="position: relative; width: 100%; height:440px;">
    15021446    <div id="dq_div_chips" style="width:100%; border:1px solid #000;"></div>
     1447</div>
     1448
     1449<div class="chartWithOverlay" style="position: relative; width: 100%; height:440px;">
     1450    <div id="dq_div_fwhm" style="width:100%; border:1px solid #000;"></div>
    15031451</div>
    15041452
     
    15141462</div>
    15151463
    1516 <div class="chartWithOverlay" style="position: relative; width: 100%; height:440px;">
    1517     <div id="dq_div_fwhm" style="width:100%; border:1px solid #000;"></div>
    1518 </div>
    1519 
    1520 
    15211464HTML;
    15221465    // End timer
  • trunk/ippMonitor/raw/getimage.php

    r41730 r43071  
    9696/* --site=$SITE */
    9797$output = array();
    98 exec ("ipp_filename.pl --site=$SITE --basename $basename --filerule $filerule --camera $camera --class_id $class_id 2> /tmp/errors", $output, $status);
     98//exec ("ipp_filename.pl --site=$SITE --basename $basename --filerule $filerule --camera $camera --class_id $class_id 2> /tmp/errors", $output, $status);
     99exec ("ipp_filename.pl --site=$SITE --basename $basename --filerule $filerule --camera $camera --class_id $class_id 2>&1", $output, $status);
     100
     101if ($debug) {
     102  echo "DEBUG  3.5<br>";
     103  for ($i = 0; $i < count($output); $i++) {
     104    echo "output x $i: $output[$i]<br>";
     105  }
     106  echo "status xx:   $status<br>";
     107
     108}
    99109
    100110# use these to check the environment
  • trunk/ippMonitor/raw/pointing.php

    r42972 r43071  
    2929echo "<tr>";
    3030echo "  <td style=width:1240>";
    31 echo "    <h1 align=\"middle\">Data Quality Report</h1>";
     31echo "    <h1 align=\"middle\">Pointing Report</h1>";
    3232
    3333#
     
    7272
    7373echo getPointing($projectdb, $range, $proj);
     74echo "<div class=\"chartWithOverlay\" style=\"position: relative; width: 100%; height:200px;\"></div>";
     75
    7476menu_end();
    7577
  • trunk/ippMonitor/raw/showimage.php

    r42384 r43071  
    66global $DBHOST;
    77
    8 $debug = 0;
     8$debug = 1;
    99$sheet = 'ipp.css';
    1010
     
    3030  echo "basename: $basename<br>";
    3131  echo "filerule: $filerule<br>";
    32   echo "filerule: $filerule<br>";
    3332  echo "camera:   $camera<br>";
    3433  echo "class_id: $class_id<br>";
    35   exit ();
     34 // exit ();
    3635}
    3736
  • trunk/ippMonitor/raw/site.php.in

    r41730 r43071  
    66$WWWHOST    = "@HOST@";
    77
    8 $PERLLIB    = "@PERLLIB@";
     8$PERLLIB    = "@PERLLIB@:@PERLLIB@/perl5:@PERLLIB@/perl5/site_perl";
    99$BINDIR     = "@BINDIR@";
    1010$WWWBIN     = "@WWWBIN@";
Note: See TracChangeset for help on using the changeset viewer.