/** * Documentation for this function. */ function makeSummaryStatsTable($resolution, $clash, $rama, $rota, $cbdev, $pperp, $suites, $bbonds, $bangles, $cablam, $omega) { $entry = ""; $bgPoor = '#ff9999'; $bgFair = '#ffff99'; $bgGood = '#99ff99'; $entry .= "<p><table border='1' width='100%'>\n"; if (is_array($clash)) { $clashPct = runClashStats($resolution, $clash['scoreAll'], $clash['scoreBlt40']); if ($clashPct['pct_rank'] < 33) { $bg = $bgPoor; } elseif ($clashPct['pct_rank'] < 66) { $bg = $bgFair; } else { $bg = $bgGood; } if ($clash['scoreAll'] < 0) { $bg = $bgFair; } // for catching a bug with probe giving clashscore = -1 $entry .= "<tr><td rowspan='2' align='center'>All-Atom<br>Contacts</td>\n"; $entry .= "<td>Clashscore, all atoms:</td><td colspan='2' bgcolor='{$bg}'>{$clash['scoreAll']}</td>\n"; if ($clash['scoreAll'] < 0) { $entry .= "<td>unknown percentile<sup>*</sup> (N={$clashPct['n_samples']}, {$clashPct['minresol']}Å - {$clashPct['maxresol']}Å)</td></tr>\n"; $entry .= "<tr><td colspan='3'>An error has occurred; clashscore should not be negative! Please report this bug.</td></tr>\n"; } else { //$entry .= "<td>$clashPct[pct_rank]<sup>".ordinalSuffix($clashPct['pct_rank'])."</sup> percentile<sup>*</sup> (N=$clashPct[n_samples], $clashPct[minresol]Å - $clashPct[maxresol]Å)</td></tr>\n"; if ($clashPct[minresol] == 0 && $clashPct[maxresol] == 9999) { $percentileOut = "all resolutions"; } else { $diff = $resolution - $clashPct[minresol]; //echo $diff." ".gettype($diff)." "; $diff2 = -($resolution - $clashPct[maxresol]); //echo $diff2." ".gettype($diff2)." "; //$test = ($diff2 > 0.245 && $diff2 < 0.255); //echo "diff2 = 0.25:".$test; if ($diff > 0.245 && $diff2 > 0.245 && $diff < 0.255 && $diff2 < 0.255) { $percentileOut = "{$resolution}Å ± {$diff}Å"; } else { $percentileOut = "{$clashPct['minresol']}Å - {$clashPct['maxresol']}Å"; } } $entry .= "<td>{$clashPct['pct_rank']}<sup>" . ordinalSuffix($clashPct['pct_rank']) . "</sup> percentile<sup>*</sup> (N={$clashPct['n_samples']}, {$percentileOut})</td></tr>\n"; $entry .= "<tr><td colspan='4'>Clashscore is the number of serious steric overlaps (> 0.4 Å) per 1000 atoms.</td></tr>\n"; } //if($clashPct['pct_rank40'] <= 33) $bg = $bgPoor; //elseif($clashPct['pct_rank40'] <= 66) $bg = $bgFair; //else $bg = $bgGood; //$entry .= "<tr><td>Clashscore, B<40:</td><td bgcolor='$bg'>$clash[scoreBlt40]</td>\n"; //$entry .= "<td>$clashPct[pct_rank40]<sup>".ordinalSuffix($clashPct['pct_rank40'])."</sup> percentile<sup>*</sup> (N=$clashPct[n_samples], $clashPct[minresol]Å - $clashPct[maxresol]Å)</td></tr>\n"; } $proteinRows = 0; if (is_array($rama)) { $proteinRows += 2; } if (is_array($rota)) { $proteinRows += 2; } if (is_array($cbdev)) { $proteinRows += 1; } if (is_array($clash) && is_array($rota) && is_array($rama)) { $proteinRows += 1; } if (hasMoltype($bbonds, "protein")) { $proteinRows += 1; } if (hasMoltype($bangles, "protein")) { $proteinRows += 1; } if ($proteinRows > 0) { $entry .= "<tr><td rowspan='{$proteinRows}' align='center'>Protein<br>Geometry</td>\n"; $firstRow = true; if (is_array($rota)) { $rotaOut = count(findRotaOutliers($rota)); $rotaTot = count($rota); $rotaOutPct = sprintf("%.2f", 100.0 * $rotaOut / $rotaTot); if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } //Rotamer outliers: //if($rotaOutPct+0 <= 1) $bg = $bgGood; //old top500 cutoff, matched outlier cutoff pct if ($rotaOutPct + 0 <= 0.3) { $bg = $bgGood; } elseif ($rotaOutPct + 0 <= 1.5) { $bg = $bgFair; } else { $bg = $bgPoor; } $entry .= "<td>Poor rotamers</td><td bgcolor='{$bg}'>{$rotaOut}</td><td bgcolor='{$bg}'>{$rotaOutPct}%</td>\n"; $entry .= "<td>Goal: <0.3%</td></tr>\n"; //Rotamer Favored: foreach ($rota as $r) { if ($r['eval'] == "Favored") { $rotaFav++; } } $rotaFavPct = sprintf("%.2f", 100.0 * $rotaFav / $rotaTot); if ($rotaFavPct + 0 >= 98) { $bg = $bgGood; } elseif ($rotaFavPct + 0 >= 95) { $bg = $bgFair; } else { $bg = $bgPoor; } $entry .= "<tr><td>Favored rotamers</td><td bgcolor='{$bg}'>{$rotaFav}</td><td bgcolor='{$bg}'>{$rotaFavPct}%</td>\n"; $entry .= "<td>Goal: >98%</td></tr>\n"; } if (is_array($rama)) { $ramaOut = count(findRamaOutliers($rama)); foreach ($rama as $r) { if ($r['eval'] == "Favored") { $ramaFav++; } } $ramaTot = count($rama); $ramaOutPct = sprintf("%.2f", 100.0 * $ramaOut / $ramaTot); $ramaFavPct = sprintf("%.2f", 100.0 * $ramaFav / $ramaTot); if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } if ($ramaOutPct + 0 <= 0.05) { $bg = $bgGood; } elseif ($ramaOut == 1 || $ramaOutPct + 0 <= 0.5) { $bg = $bgFair; } else { $bg = $bgPoor; } $entry .= "<td>Ramachandran outliers</td><td bgcolor='{$bg}'>{$ramaOut}</td><td bgcolor='{$bg}'>{$ramaOutPct}%</td>\n"; $entry .= "<td>Goal: <0.05%</td></tr>\n"; if ($ramaFavPct + 0 >= 98) { $bg = $bgGood; } elseif ($ramaFavPct + 0 >= 95) { $bg = $bgFair; } else { $bg = $bgPoor; } $entry .= "<tr><td>Ramachandran favored</td><td bgcolor='{$bg}'>{$ramaFav}</td><td bgcolor='{$bg}'>{$ramaFavPct}%</td>\n"; $entry .= "<td>Goal: >98%</td></tr>\n"; } if (is_array($clash) && is_array($rota) && is_array($rama)) { if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } $axr = $resolution; // Actual Xtalographic Resolution $mer = getEffectiveResolution($clash, $rota, $rama); // MolProbity Effective Resolution $mer_pct = getEffectiveResolutionPercentile($mer, $axr); /*if(!$axr)*/ $bg = $bgFair; // unknown AXR //elseif($mer < $axr) $bg = $bgGood; // below //elseif(abs(($mer-$axr)/$axr) <= 0.20) $bg = $bgFair; // within 20% of actual //else $bg = $bgPoor; // more than 20% above if ($mer_pct['pct_rank'] < 33) { $bg = $bgPoor; } // switch to using percentiles for bg colors vbc 120629 if ($mer_pct['pct_rank'] >= 66) { $bg = $bgGood; } // to try to compensate for high-res structures looking worse than they are if (is_infinite($mer)) { $mer = -1; $bg = $bgFair; } $entry .= "<td>MolProbity score<sup><small>^</small></sup></td><td colspan='2' bgcolor='{$bg}'>"; $entry .= sprintf('%.2f', $mer); //$entry .= "</td><td>Goal: <$axr</td></tr>\n"; if ($mer == -1) { $entry .= "</td><td>unknown percentile<sup>*</sup> (N={$mer_pct['n_samples']}, {$mer_pct['minresol']}Å - {$mer_pct['maxresol']}Å)</td></tr>\n"; } else { if ($mer_pct[minresol] == 0 && $mer_pct[maxresol] == 9999) { $percentileOut = "all resolutions"; } else { $diff = $resolution - $mer_pct[minresol]; $diff2 = -($resolution - $mer_pct[maxresol]); if ($diff > 0.245 && $diff2 > 0.245 && $diff < 0.255 && $diff2 < 0.255) { $percentileOut = "{$resolution}Å ± {$diff}Å"; } else { $percentileOut = "{$mer_pct['minresol']}Å - {$mer_pct['maxresol']}Å"; } } $entry .= "</td><td>{$mer_pct['pct_rank']}<sup>" . ordinalSuffix($mer_pct['pct_rank']) . "</sup> percentile<sup>*</sup> (N={$mer_pct['n_samples']}, {$percentileOut})</td></tr>\n"; //$entry .= "</td><td>$mer_pct[pct_rank]<sup>".ordinalSuffix($mer_pct['pct_rank'])."</sup> percentile<sup>*</sup> (N=$mer_pct[n_samples], $mer_pct[minresol]Å - $mer_pct[maxresol]Å)</td></tr>\n"; } } if (is_array($cbdev)) { $cbOut = count(findCbetaOutliers($cbdev)); $cbTot = count($cbdev); $cbOutPct = sprintf("%.2f", 100.0 * $cbOut / $cbTot); if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } if ($cbOut == 0) { $bg = $bgGood; } else { $bg = $bgFair; } if ($cbOut / $cbTot > 0.05) { $bg = $bgPoor; } $entry .= "<td>Cβ deviations >0.25Å</td><td bgcolor='{$bg}'>{$cbOut}</td><td bgcolor='{$bg}'>{$cbOutPct}%</td>\n"; $entry .= "<td>Goal: 0</td></tr>\n"; } if (hasMoltype($bbonds, "protein")) { if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } $total = 0; $outCount = 0; foreach ($bbonds as $cnit => $item) { if ($item['type'] == 'protein') { if ($item['isOutlier']) { $outCount += $item['outCount']; } $total += $item['bondCount']; } } $geomOutPct = sprintf("%.2f", 100.0 * $outCount / $total); if ($outCount / $total < 0.002) { $bg = $bgFair; } if ($outCount / $total < 0.0001) { $bg = $bgGood; } else { $bg = $bgPoor; } $entry .= "<td>Bad bonds:</td><td bgcolor='{$bg}'>{$outCount} / {$total}</td><td bgcolor='{$bg}'>{$geomOutPct}%</td>\n<td>Goal: 0%</td></tr>\n"; } if (hasMoltype($bangles, "protein")) { if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } $total = 0; $outCount = 0; foreach ($bangles as $cnit => $item) { if ($item['type'] == 'protein') { if ($item['isOutlier']) { $outCount += $item['outCount']; } $total += $item['angCount']; } } $geomOutPct = sprintf("%.2f", 100.0 * $outCount / $total); if ($outCount / $total < 0.005) { $bg = $bgFair; } if ($outCount / $total < 0.001) { $bg = $bgGood; } else { $bg = $bgPoor; } $entry .= "<td>Bad angles:</td><td bgcolor='{$bg}'>{$outCount} / {$total}</td><td bgcolor='{$bg}'>{$geomOutPct}%</td>\n<td>Goal: <0.1%</td></tr>\n"; } } // end of protein-specific stats if (is_array($omega)) { $totalres = 0; $prototal = 0; $nonprototal = 0; $cisprocount = 0; $cisnonprocount = 0; $twistcount = 0; foreach ($omega as $cnit => $item) { //$totalres += 1; if ($item['type'] == 'Pro') { $prototal += 1; if ($item['conf'] == 'Cis') { $cisprocount += 1; } elseif ($item['conf'] == 'Twisted') { $twistcount += 1; } } elseif ($item['type'] == 'General') { $nonprototal += 1; if ($item['conf'] == 'Cis') { $cisnonprocount += 1; } elseif ($item['conf'] == 'Twisted') { $twistcount += 1; } } } $totalres = $prototal + $nonprototal; $cispropct = sprintf("%.2f", 100.0 * $cisprocount / $prototal); $cisnonpropct = sprintf("%.2f", 100.0 * $cisnonprocount / $nonprototal); $twistpct = sprintf("%.2f", 100.0 * $twistcount / $totalres); //stoplights: //cis pro yellow is 5 to 10% //cis nonpro is 0.05 to 0.1% //twisted is 0 to 0.1% //This is gonna get ugly. The trick is: always print the cisPRO line //Print other lines only if relevant $cispepentry = ""; $cispepRows = 1; //if($cispropct <= 5.0) $bg = $bgGood; //5% is statistical expectation for cis-Pro //elseif($cispropct <= 10.0) $bg = $bgFair; //set at 2x statistical expectations //else $bg = $bgPoor; $cisentry .= "<td>Cis Prolines:</td><td> {$cisprocount} / {$prototal}</td><td> {$cispropct}% </td>\n<td>Expected: ≤1 per chain, or ≤5%</td></tr>\n"; if ($cisnonprocount > 0) { $cispepRows += 1; if ($cisnonpropct <= 0.05) { $bg = $bgGood; } elseif ($cisnonpropct <= 0.1) { $bg = $bgFair; } else { $bg = $bgPoor; } $cisentry .= "<td>Cis nonProlines:</td><td bgcolor='{$bg}'> {$cisnonprocount} / {$nonprototal}</td><td bgcolor='{$bg}'> {$cisnonpropct}% </td>\n<td>Goal: <0.05%</td></tr>\n"; } if ($twistcount > 0) { $cispepRows += 1; if ($twistpct == 0) { $bg = $bgGood; } elseif ($twistpct <= 0.1) { $bg = $bgFair; } else { $bg = $bgPoor; } $cisentry .= "<td>Twisted Peptides:</td><td bgcolor='{$bg}'> {$twistcount} / {$totalres}</td><td bgcolor='{$bg}'> {$twistpct}% </td>\n<td>Goal: 0</td></tr>\n"; } $entry .= "<tr><td rowspan='{$cispepRows}' align='center'>Peptide Omegas</td>\n"; $firstRow = true; $entry .= $cisentry; } $nucleicRows = 0; if (is_array($pperp)) { $nucleicRows += 1; } if (is_array($suites)) { $nucleicRows += 1; } if (hasMoltype($bbonds, "rna")) { $nucleicRows += 1; } if (hasMoltype($bangles, "rna")) { $nucleicRows += 1; } if ($nucleicRows > 0) { $entry .= "<tr><td rowspan='{$nucleicRows}' align='center'>Nucleic Acid<br>Geometry</td>\n"; $firstRow = true; if (is_array($pperp)) { if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } $pperpOut = count(findBasePhosPerpOutliers($pperp)); $pperpTot = count($pperp); $pperpOutPct = sprintf("%.2f", 100.0 * $pperpOut / $pperpTot); $bg = $bgFair; if ($pperpOut == 0) { $bg = $bgGood; } if ($pperpOut / $pperpTot > 0.05) { $bg = $bgPoor; } $entry .= "<td>Probably wrong sugar puckers:</td><td bgcolor='{$bg}'>{$pperpOut}</td><td bgcolor='{$bg}'>{$pperpOutPct}%</td>\n"; $entry .= "<td>Goal: 0</td></tr>\n"; } if (is_array($suites)) { if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } $suitesOut = count(findSuitenameOutliers($suites)); $suitesTot = count($suites); $suitesOutPct = sprintf("%.2f", 100.0 * $suitesOut / $suitesTot); $bg = $bgFair; if ($suitesOut / $suitesTot <= 0.05) { $bg = $bgGood; } if ($suitesOut / $suitesTot > 0.15) { $bg = $bgPoor; } $entry .= "<td>Bad backbone conformations<sup><small>#</small></sup>:</td><td bgcolor='{$bg}'>{$suitesOut}</td><td bgcolor='{$bg}'>{$suitesOutPct}%</td>\n"; $entry .= "<td>Goal: <= 5%</td></tr>\n"; } if (hasMoltype($bbonds, "rna")) { if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } $total = 0; $outCount = 0; foreach ($bbonds as $cnit => $item) { if ($item['type'] == 'rna') { if ($item['isOutlier']) { $outCount += $item['outCount']; } $total += $item['bondCount']; } } $geomOutPct = sprintf("%.2f", 100.0 * $outCount / $total); if ($outCount / $total < 0.002) { $bg = $bgFair; } if ($outCount / $total < 0.0001) { $bg = $bgGood; } else { $bg = $bgPoor; } $entry .= "<td>Bad bonds:</td><td bgcolor='{$bg}'>{$outCount} / {$total}</td><td bgcolor='{$bg}'>{$geomOutPct}%</td>\n<td>Goal: 0%</td></tr>\n"; } if (hasMoltype($bangles, "rna")) { if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } $total = 0; $outCount = 0; foreach ($bangles as $cnit => $item) { if ($item['type'] == 'rna') { if ($item['isOutlier']) { $outCount += $item['outCount']; } $total += $item['angCount']; } } $geomOutPct = sprintf("%.2f", 100.0 * $outCount / $total); if ($outCount / $total < 0.005) { $bg = $bgFair; } if ($outCount / $total < 0.001) { $bg = $bgGood; } else { $bg = $bgPoor; } $entry .= "<td>Bad angles:</td><td bgcolor='{$bg}'>{$outCount} / {$total}</td><td bgcolor='{$bg}'>{$geomOutPct}%</td>\n<td>Goal: <0.1%</td></tr>\n"; } } //Lowres $lowresRows = 0; if (is_array($cablam)) { $lowresRows += 2; } if ($lowresRows > 0) { //Following text should be added to help instead of entry: //$entry .= "<td>Because the submitted structure has a resolution lower than 2.5Å or because low-resolution measures were selected, the following criteria are provided that may be helpful at low resolution.</td></tr>\n"; $entry .= "<tr><td rowspan='{$lowresRows}' align='center'>Low-resolution Criteria</td>\n"; $firstRow = true; if (is_array($cablam)) { $cablamOut = 0; $caGeomOut = 0; //$cablamFav = 0; foreach ($cablam as $c) { if ($c['outlierType'] == " CaBLAM Outlier ") { $cablamOut++; } elseif ($c['outlierType'] == " CA Geom Outlier ") { $caGeomOut++; } //elseif($c['outlierType'] != " CaBLAM Disfavored ") $cablamFav++; //The disfavored category was deemed more info than necessary for the moment in this chart } $cablamTot = count($cablam); $cablamOutPct = sprintf("%.2f", 100.0 * $cablamOut / $cablamTot); //$cablamFavPct = sprintf("%.2f", 100.0 * $cablamFav/$cablamTot); $caGeomPct = sprintf("%.2f", 100.0 * $caGeomOut / $cablamTot); if ($firstRow) { $firstRow = false; } else { $entry .= "<tr>"; } //CaBLAMout 1% and 5% if ($cablamOutPct + 0 <= 1.0) { $bg = $bgGood; } elseif ($cablamOutPct + 0 <= 5.0) { $bg = $bgFair; } else { $bg = $bgPoor; } $entry .= "<td>CaBLAM outliers</td><td bgcolor='{$bg}'>{$cablamOut}</td><td bgcolor='{$bg}'>{$cablamOutPct}%</td>\n"; $entry .= "<td>Goal: <1.0%</td></tr>\n"; //if($cablamFavPct+0 >= 95.0) $bg = $bgGood; //elseif($cablamFavPct+0 >=90.0) $bg = $bgFair; //else $bg = $bgPoor; //$entry .= "<tr><td>CaBLAM favored</td><td bgcolor='$bg'>$cablamFav</td><td bgcolor='$bg'>$cablamFavPct%</td>\n"; //$entry .= "<td>Goal: >95.0%</td></tr>\n"; if ($caGeomPct + 0 <= 0.5) { $bg = $bgGood; } elseif ($caGeomPct + 0 <= 1.0) { $bg = $bgFair; } else { $bg = $bgPoor; } $entry .= "<tr><td>CA Geometry outliers</td><td bgcolor='{$bg}'>{$caGeomOut}</td><td bgcolor='{$bg}'>{$caGeomPct}%</td>\n"; $entry .= "<td>Goal: <0.5%</td></tr>\n"; } } $entry .= "</table>\n"; //Table ended $firstRow = true; if (is_array($rota) || is_array($rama) || is_array($cbdev) || is_array($bbonds) || is_array($bangles) || is_array($pperp) || is_array($suites)) { if ($firstRow) { $firstRow = false; } else { $entry .= "<br>"; } $entry .= "<small>In the two column results, the left column gives the raw count, right column gives the percentage.</small>\n"; } if (is_array($clash)) { if ($firstRow) { $firstRow = false; } else { $entry .= "<br>"; } $entry .= "<small>* 100<sup>th</sup> percentile is the best among structures of comparable resolution; 0<sup>th</sup> percentile is the worst. For clashscore the comparative set of structures was selected in 2004, for MolProbity score in 2006.</small>\n"; } if (is_array($suites)) { if ($firstRow) { $firstRow = false; } else { $entry .= "<br>"; } $entry .= "<small><sup>#</sup> RNA backbone was recently shown to be rotameric. Outliers are RNA suites that don't fall into recognized rotamers.</small>\n"; } if (is_array($clash) && is_array($rota) && is_array($rama)) { if ($firstRow) { $firstRow = false; } else { $entry .= "<br>"; } //$entry .= "<small><sup>^</sup> MolProbity score is defined as the following: 0.42574*log(1+clashscore) + 0.32996*log(1+max(0,pctRotOut-1)) + 0.24979*log(1+max(0,100-pctRamaFavored-2)) + 0.5</small>\n"; $entry .= "<small><sup>^</sup> MolProbity score combines the clashscore, rotamer, and Ramachandran evaluations into a single score, normalized to be on the same scale as X-ray resolution.</small>\n"; } $entry .= "</p>\n"; // end of summary stats table return $entry; }
function short_date($date) { $minute = $date['minutes']; $minute = $minute < 10 ? '0' . $minute : (string) $minute; $ordinal = ordinalSuffix($date['mday']); if ($date['hours'] == '12') { $hour = '12'; $ampm = 'pm'; } else { if ($date['hours'] == '24') { $hour = '12'; $ampm = 'am'; } else { if ($date['hours'] > 12) { $hour = (int) $date['hours'] - 12; $ampm = 'pm'; } else { $hour = $date['hours']; $ampm = 'am'; } } } return "{$date['month']} {$date['mday']}{$ordinal} @ {$hour}:{$minute}{$ampm}"; }