function tree2kml($obj, $default_labels = 'taxa') { $t = new Tree(); $t->Parse($obj->tree->newick); $t->BuildWeights($t->GetRoot()); // compute KML coordinates $attr = array(); $td = new KmlTreeDrawer($t, $attr); $td->CalcCoordinates(); // raw labels (OTUs) // $port->StartGroup('otu', (('otu' == $default_labels) || !isset($obj->translations)) ); $kml = ''; $kml .= "<?xml version =\"1.0\" encoding=\"UTF-8\"?>\n"; $kml .= "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n"; $kml .= "<Document>\n"; $kml .= "<Style id=\"treeLine\">\n"; $kml .= "<LineStyle><color>7fffffff</color><width>2</width></LineStyle>\n"; $kml .= "</Style>\n"; $kml .= "<Style id=\"whiteBall\">\n"; $kml .= "<IconStyle>\n"; $kml .= "<Icon>\n"; $kml .= "<href>http://iphylo.org/~rpage/phyloinformatics/images/whiteBall.png</href>\n"; $kml .= "</Icon>\n"; $kml .= "</IconStyle>\n"; $kml .= "<LineStyle>\n"; $kml .= "<width>2</width>\n"; $kml .= "</LineStyle>\n"; $kml .= "</Style>\n"; $td->Draw(null); $kml .= $td->kml; $kml .= "<Folder>\n"; $kml .= "<name>Labels</name>\n"; // labels $ni = new NodeIterator($t->getRoot()); $q = $ni->Begin(); while ($q != NULL) { if ($q->IsLeaf()) { $kml .= "<Placemark>\n"; $kml .= "<name>" . $q->Getlabel() . "</name>\n"; $kml .= "<styleUrl>#whiteBall</styleUrl>\n"; $kml .= "<Point>\n"; $kml .= "<altitudeMode>absolute</altitudeMode>\n"; $kml .= "<extrude>1</extrude>\n"; $kml .= "<coordinates>\n"; $kml .= $q->GetAttribute('long') . "," . $q->GetAttribute('lat') . "," . $q->GetAttribute('altitude') . "\n"; $kml .= "</coordinates>\n"; $kml .= "</Point>\n"; $kml .= "</Placemark>\n"; } $q = $ni->Next(); } $kml .= "</Folder>\n"; $kml .= "</Document>\n"; $kml .= "</kml>\n"; echo $kml; }
function main() { global $matching_path; $have_tree = false; $have_taxa = false; $have_table = false; $newick = ''; if (isset($_POST['tree'])) { $obj = parse_nexus(stripcslashes($_POST['tree'])); $taxa = get_taxa_from_tree($obj); $newick = $obj->tree->newick; //echo $newick; //print_r($obj); $t = new Tree(); $t->Parse($newick); $ni = new NodeIterator($t->getRoot()); $q = $ni->Begin(); while ($q != NULL) { if ($q->IsLeaf()) { if (isset($obj->translations->translate)) { $q->SetLabel($obj->translations->translate[$q->GetLabel()]); } } $q = $ni->Next(); } $newick = $t->WriteNewick(); //echo $newick; $have_tree = true; } if (isset($_POST['taxa'])) { $have_taxa = true; } if (isset($_POST['table'])) { $table = $_POST['table']; $have_table = true; } if (isset($_POST['newick'])) { $newick = $_POST['newick']; } if ($have_tree || $have_taxa) { if ($have_table) { // get taxa $taxa = explode("\n", stripcslashes($_POST['taxa'])); $n = count($taxa); for ($i = 0; $i < $n; $i++) { $taxa[$i] = trim($taxa[$i]); } // get table data $table = stripcslashes($_POST['table']); // Interpret table automatically... // assume column one contains OTUs, and some other column(s) have lat and long $data = extract_table($table); //print_r($data); if (count($taxa) != count($data)) { echo '<html> <head> <meta charset="utf-8" /> <style type="text/css" title="text/css"> body { font-family:sans-serif;padding:20px; } </style> <title>Create KML tree - Error</title> </head> <body> <a href=".">Back</a> <h1>Error</h1> <p>The number of taxa in the tree (' . count($taxa) . ') does not match the number in the table (' . count($data) . ')</p> </body> </html>'; exit; } $data_lookup_by_label = array(); foreach ($data as $d) { $data_lookup_by_label[$d->label] = $d; } // show matching... /* echo ' <form method="post" action="."> <table border="1">'; echo '<tr><th>Taxa in tree</th><th>Taxa in table</th><th>Latitude</th><th>Longitude</th></tr>'; $nrows = count($data); for ($i=0;$i < $nrows; $i++) { echo '<tr>'; echo '<td>' . $taxa[$i] . '</td>'; echo '<td>' . $data[$i]->label . '</td>'; echo '<td>' . $data[$i]->latlong['latitude'] . '</td>'; echo '<td>' . $data[$i]->latlong['longitude'] . '</td>'; echo '</td></tr>'; } echo '</table> <input type="submit" value="Go"></input> </form>'; */ // build graph for matching // Create GML file for graph linking taxon labels in tree and table // Taxon labels in table $b = array(); foreach ($data as $row) { $b[] = $row->label; } $filename = 'tmp/' . uniqid() . '.gml'; $gml = create_graph($taxa, $b); file_put_contents($filename, $gml); //echo $gml; // Compute maximum weight bipartite matching $command = $matching_path . 'matching ' . $filename; $output = array(); exec($command, $output); //echo $command; $json = join("", $output); //echo $json; $match = json_decode($json); if (0) { echo '<pre>'; $n = count($taxa); foreach ($match->matching as $pair) { echo $taxa[$pair[0]] . "|\t" . $b[$pair[1] - $n] . "\n"; } echo '</pre>'; } // Mapping between tree labels and table labels $match_by_label = array(); $n = count($taxa); foreach ($match->matching as $pair) { $match_by_label[$taxa[$pair[0]]] = $b[$pair[1] - $n]; } // match and build KML file $t = new Tree(); $t->Parse($newick); $t->BuildWeights($t->GetRoot()); //echo $newick; $ni = new NodeIterator($t->getRoot()); $q = $ni->Begin(); while ($q != NULL) { if ($q->IsLeaf()) { $data = $data_lookup_by_label[$match_by_label[$q->GetLabel()]]; $q->SetAttribute('lat', $data->latlong['latitude']); $q->SetAttribute('long', $data->latlong['longitude']); } $q = $ni->Next(); } // KML... //echo '<pre>'; //$t->Dump(); //echo '</pre>'; $kml = tree2kml($t); echo '<html> <head> <meta charset="utf-8" /> <style type="text/css" title="text/css"> body { font-family:sans-serif;padding:20px; } </style> <title>Create KML tree - Step 3</title> <script type="text/javascript" src="https://www.google.com/jsapi"> </script> <script type="text/javascript"> var ge; google.load("earth", "1"); function init() { google.earth.createInstance(\'map3d\', initCB, failureCB); } function initCB(instance) { ge = instance; ge.getWindow().setVisibility(true); var treeDoc = ge.parseKml('; $kml_lines = explode("\n", $kml); $k = join(" ", $kml_lines); echo "'" . $k . "'"; echo '); ge.getFeatures().appendChild(treeDoc); } function failureCB(errorCode) { } google.setOnLoadCallback(init); </script> </head> <body> <a href=".">Home</a> <h1>Step 3: Match tree to table and create KML</h1>'; // Display mapping echo '<h2>Tree and table matching</h2>'; echo '<table border="1">'; echo '<tr><th>Taxa in tree</th><th>Taxa in table</th><th>Latitude</th><th>Longitude</th></tr>'; $n = count($taxa); foreach ($match->matching as $pair) { echo '<tr>'; echo '<td>'; echo $taxa[$pair[0]]; echo '</td>'; $data = $data_lookup_by_label[$match_by_label[$taxa[$pair[0]]]]; echo '<td>' . $data->label . '</td>'; echo '<td>' . $data->latlong['latitude'] . '</td>'; echo '<td>' . $data->latlong['longitude'] . '</td>'; echo '</tr>'; } echo '</table>'; echo '<h2>KML</h2>'; echo '<textarea rows="30" cols="100">'; echo $kml; echo '</textarea>'; echo '<h2>Google Earth plugin</h2>'; echo ' <div id="map3d" style="height: 400px; width: 600px;"></div>'; echo '</body> </html>'; } else { // We have the tree but no data yet echo '<html> <head> <meta charset="utf-8" /> <style type="text/css" title="text/css"> body { font-family:sans-serif;padding:20px; } </style> <title>Create KML tree - Step 2</title> </head> <body> <a href=".">Home</a> <h1>Step 2: Add table</h1> <form method="post" action="."> <input name="newick" type="hidden" value="' . $newick . '"> <table> <tr><th>Taxa in tree</th><th>Paste in table with taxa (in first column), and latitude and longitude.<br/>The first row of the table must contain column headings.</th></tr> <tr> <td> <textarea id="taxa" name="taxa" rows="30" cols="60" readonly="readonly">' . join("\n", $taxa) . '</textarea> </td> <td> <textarea id="table" name="table" rows="30" cols="60"></textarea> </td> </tr> </table> <input type="submit" value="Next step"></input> </form> </body> </html>'; } } else { // Starting point, get tree echo '<html> <head> <meta charset="utf-8" /> <style type="text/css" title="text/css"> body { font-family:sans-serif;padding:20px; } </style> <title>Create KML tree - Step 1</title> </head> <body> <h1>Step 1: Paste in a tree in NEXUS format</h1> <form method="post" action="."> <textarea id="tree" name="tree" rows="30" cols="60"></textarea> <br /> <input type="submit" value="Next step"></input> </form> </body> </html>'; } }
/** * @begin Draw tree and labels in SVG * * @param width Width (pixels) to draw tree + labels in * @param height * @param label_space Width (pixels) of space to draw leaf labels in * @param font_height Height of font to use to draw labels * @param default_labels Name of group of labels to show by default * */ function tree2svg($obj, $width = 400, $height = 400, $label_space = 150, $font_height = 10, $force_height = false, $default_labels = 'taxa') { //---------------------------------------------------------------------------------------------- $t = new Tree(); $t->Parse($obj->tree->newick); $t->BuildWeights($t->GetRoot()); $tree_width = $width - $label_space; if (!$force_height) { // adjust height to accomodate tree $height = $t->GetNumLeaves() * ($font_height + $font_height / 3); $inset = $font_height; } else { $inset = 0; } // Drawing properties $attr = array(); $attr['inset'] = $inset; $attr['width'] = $tree_width; $attr['height'] = $height; $attr['font_height'] = $font_height; $attr['line_width'] = 1; // Don't draw labels (we do this afterwards) $attr['draw_leaf_labels'] = false; $attr['draw_internal_labels'] = false; $td = NULL; if ($t->HasBranchLengths()) { $td = new PhylogramTreeDrawer($t, $attr); } else { $td = new RectangleTreeDrawer($t, $attr); } $td->CalcCoordinates(); if (!$force_height) { $port = new SVGPort('', $width, $td->max_height + $attr['font_height']); } else { $port = new SVGPort('', $width, $height + 2); } $port->StartGroup('tree'); $td->Draw($port); $port->EndGroup(); // labels if ($label_space > 0) { $ni = new NodeIterator($t->getRoot()); // raw labels (OTUs) $port->StartGroup('otu', 'otu' == $default_labels || !isset($obj->translations)); $q = $ni->Begin(); while ($q != NULL) { if ($q->IsLeaf()) { $p0 = $q->GetAttribute('xy'); $p0['x'] += $font_height / 3; $text = $q->Getlabel(); $text = str_replace("_", " ", $text); $action = 'onclick="node_info(\'' . htmlentities($text) . '\');"'; $port->DrawText($p0, $text, $action); } $q = $ni->Next(); } $port->EndGroup(); if ($obj->translations) { // Tree has a one or more translation tables foreach ($obj->translations as $k => $v) { // Draw labels as a separate group $port->StartGroup($k, $k == $default_labels ? true : false); $q = $ni->Begin(); while ($q != NULL) { if ($q->IsLeaf()) { $p0 = $q->GetAttribute('xy'); $p0['x'] += $font_height / 3; $label = $q->Getlabel(); if (is_array($v)) { if (isset($v[$label])) { $label = $v[$label]; } else { // No translation for this OTU $label = '[' . $label . ']'; } } else { if (isset($v->{$label})) { $label = $v->{$label}; } else { // No translation for this OTU $label = '[' . $label . ']'; } } $action = 'onclick="node_info(\'' . $q->Getlabel() . '\');"'; $port->DrawText($p0, $label, $action); } $q = $ni->Next(); } $port->EndGroup(); } } } $svg = $port->GetOutput(); return $svg; }