Skip to content

Commit

Permalink
Merge pull request #43 from glycojones/torsion_plots
Browse files Browse the repository at this point in the history
Adding torsion plots to GlycanDetail display
  • Loading branch information
Dialpuri authored Sep 20, 2023
2 parents 35963b3 + a825d38 commit 7fed532
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 164 deletions.
68 changes: 50 additions & 18 deletions src/privateer/cpp/clipper-glyco.cpp

Large diffs are not rendered by default.

13 changes: 4 additions & 9 deletions src/privateer/cpp/clipper-glyco.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ namespace clipper
clipper::String second_residue_name; // acceptorResidue
std::vector<std::pair<clipper::MAtom, clipper::MAtom>> atoms; // .first = donorAtom, .second = acceptorAtom
std::vector<std::pair<std::string, std::string>> linkage_descriptors; // .first = donorPosition, .second = acceptorPosition
std::vector<std::pair<std::pair<std::string, std::string>, std::vector<std::pair<float,float>>>> combined_torsions; // This needs to be changed
std::vector<std::pair<float, float>> torsions; // .first = Phi, .second = Psi
};

Expand Down Expand Up @@ -831,18 +832,12 @@ namespace clipper
}; // class Node

bool link_sugars ( int link, clipper::MSugar& first_sugar, clipper::MSugar& next_sugar, clipper::MAtom& donorAtom, clipper::MAtom& acceptorAtom, bool noncircular, privateer::json::GlobalTorsionZScore& torsions_zscore_database ); // true if there's been any problem
void add_torsions_for_detected_linkages(float Phi, float Psi, clipper::String first_residue_name, clipper::MAtom first_atom, clipper::String second_residue_name, clipper::MAtom second_atom);
void add_torsions_for_detected_linkages(float Phi, float Psi, clipper::String first_residue_name, clipper::MAtom first_atom, clipper::String second_residue_name, clipper::MAtom second_atom, int first_residue_seqnum, int second_residue_seqnum);
std::vector<MGlycanTorsionSummary> return_torsion_summary_within_glycan() { return all_torsions_within_mglycan; };
const std::pair < clipper::MMonomer, clipper::MSugar >& get_root () const { return this->root; }
const clipper::String& get_type () const { return kind_of_glycan; } // n-glycan, o-glycan, s-glycan, c-glycan, p-glycan or ligand
// std::string get_root_by_name () const { return get_root().first.type().trim() + "-" + get_root().first.id().trim() + "/" + get_chain().substr(0,1); }
std::string get_root_by_name () const {
return get_root().second.type().trim() +
"-" + get_root().second.id().trim().substr(0, get_root().second.id().trim().find(":")) +
"/" + get_root_sugar_chainID().trim().substr(0,1) + "_" + get_root().first.type().trim() +
"-" + get_root().first.id().trim().substr(0, get_root().first.id().trim().find(":")) +
"/" + get_chain().substr(0,1); }

std::string get_root_by_name () const { return get_root().second.type().trim() + "-" + get_root().second.id().trim() + "/" + get_root_sugar_chainID().trim().substr(0,1) + "_" + get_root().first.type().trim() + "-" + get_root().first.id().trim() + "/" + get_chain().substr(0,1); }
std::string get_root_for_filename () { return get_root().second.type().trim() + get_root().second.id().trim() + "-[" + get_root_sugar_chainID().trim().substr(0,1) + "]_[" + get_chain().trim().substr(0,1) + "]-" + get_root().first.type().trim() + get_root().first.id().trim(); }

std::string write_ring_ext_restraints ( float weight );
Expand Down Expand Up @@ -1000,4 +995,4 @@ namespace clipper
} // namespace clipper


#endif
#endif
154 changes: 40 additions & 114 deletions src/privateer/cpp/privateer-bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ extern "C" std::vector<std::string> read_file(const std::string &file, const std
}
}

struct TorsionEntry {
std::string sugar_1;
std::string sugar_2;
std::string atom_number_1;
std::string atom_number_2;
float phi;
float psi;
};

struct TableEntry
{
std::string svg;
Expand All @@ -90,121 +99,9 @@ struct TableEntry
int puckering_err = 0;
int chirality_err = 0;

// std::vector<std::string> glycan_types;


};

struct GlycanData
{
std::string glyconnect_id;
std::string glytoucan_id;
std::string wurcs;
std::vector<TorsionEntry> torsions;
};

GlycanData
query_glycomics_database(clipper::MGlycan &currentGlycan, const std::string& WURCS, std::vector<privateer::json::GlycomicsDatabase> &glycomics_database, bool returnClosestMatches = false, bool returnAllPossiblePermutations = false, int nThreads = 1)
{

std::string currentWURCS = WURCS;

int valueLocation = privateer::util::find_index_of_value_from_wurcs(glycomics_database, WURCS);
if (!returnClosestMatches && currentGlycan.number_of_nodes() > 1)
{
if (valueLocation != -1 && glycomics_database[valueLocation].GlyConnectID != "NotFound")
{
std::string glytoucanID, glyconnectID;
glytoucanID = glycomics_database[valueLocation].GlyTouCanID;
if (glytoucanID.front() == '"' && glytoucanID.front() == '"')
{
glytoucanID.erase(0, 1);
glytoucanID.pop_back();
}
glyconnectID = glycomics_database[valueLocation].GlyConnectID;
if (glyconnectID.front() == '"' && glyconnectID.front() == '"')
{
glyconnectID.erase(0, 1);
glyconnectID.pop_back();
}

GlycanData glycan_data;
glycan_data.wurcs = currentWURCS;
glycan_data.glyconnect_id = glyconnectID;
glycan_data.glytoucan_id = glytoucanID;
return glycan_data;
}
else if (valueLocation != -1 && glycomics_database[valueLocation].GlyConnectID == "NotFound")
{
std::string glytoucanID = glycomics_database[valueLocation].GlyTouCanID;
if (glytoucanID.front() == '"' && glytoucanID.front() == '"')
{
glytoucanID.erase(0, 1);
glytoucanID.pop_back();
}

GlycanData glycan_data;
glycan_data.wurcs = currentWURCS;
glycan_data.glyconnect_id = "NotFound";
glycan_data.glytoucan_id = glytoucanID;
return glycan_data;
}
else
{
GlycanData glycan_data;
glycan_data.wurcs = currentWURCS;
glycan_data.glyconnect_id = "Not Found";
glycan_data.glytoucan_id = "NotFound";
return glycan_data;
}
}
else
{
std::string glytoucanID = "Not Found";
if (valueLocation != -1 && glycomics_database[valueLocation].GlyConnectID != "NotFound")
{
std::string glytoucanID, glyconnectID;
glytoucanID = glycomics_database[valueLocation].GlyTouCanID;
if (glytoucanID.front() == '"' && glytoucanID.front() == '"')
{
glytoucanID.erase(0, 1);
glytoucanID.pop_back();
}
glyconnectID = glycomics_database[valueLocation].GlyConnectID;
if (glyconnectID.front() == '"' && glyconnectID.front() == '"')
{
glyconnectID.erase(0, 1);
glyconnectID.pop_back();
}
GlycanData glycan_data;
glycan_data.wurcs = currentWURCS;
glycan_data.glyconnect_id = glyconnectID;
glycan_data.glytoucan_id = glytoucanID;
return glycan_data;
}
else if (valueLocation != -1 && glycomics_database[valueLocation].GlyConnectID == "NotFound")
{
std::string glytoucanID = glycomics_database[valueLocation].GlyTouCanID;
if (glytoucanID.front() == '"' && glytoucanID.front() == '"')
{
glytoucanID.erase(0, 1);
glytoucanID.pop_back();
}
GlycanData glycan_data;
glycan_data.wurcs = currentWURCS;
glycan_data.glyconnect_id = "NotFound";
glycan_data.glytoucan_id = glytoucanID;
return glycan_data;
}
else
{
GlycanData glycan_data;
glycan_data.wurcs = currentWURCS;
glycan_data.glyconnect_id = "Not Found";
glycan_data.glytoucan_id = "Not Found";
return glycan_data;
}
}
}

extern "C" std::vector<TableEntry> read_file_to_table(const std::string &file, const std::string &name)
{
Expand Down Expand Up @@ -278,7 +175,24 @@ extern "C" std::vector<TableEntry> read_file_to_table(const std::string &file, c
table_entry.chirality_err = err->chirality_err;


// std::vector<clipper::MGlycan::MGlycanTorsionSummary> list_of_glycans[i].return_torsion_summary_within_glycan()
std::vector<clipper::MGlycan::MGlycanTorsionSummary> torsion_list = list_of_glycans[i].return_torsion_summary_within_glycan();
for(int i = 0; i < torsion_list.size(); i++) {
for(int j = 0; j < torsion_list[i].combined_torsions.size(); j++)
{
std::pair<std::pair<std::string, std::string>, std::vector<std::pair<float,float>>> torsion = torsion_list[i].combined_torsions[j];
for (int k = 0; k < torsion.second.size(); k++) {
TorsionEntry te;
te.sugar_1 = torsion_list[i].first_residue_name;
te.sugar_2 = torsion_list[i].second_residue_name;
te.atom_number_1 = torsion.first.first;
te.atom_number_2 = torsion.first.second;
te.phi = torsion.second[k].first;
te.psi = torsion.second[k].second;
table_entry.torsions.emplace_back(te);
}
}
}

// table_entry.description = list_of_glycans[i].get_description();
table_list.emplace_back(table_entry);
delete err;
Expand Down Expand Up @@ -307,6 +221,16 @@ EMSCRIPTEN_BINDINGS(privateer_module)
function("read_structure", &read_file);
register_vector<std::string>("vector<string>");

value_object<TorsionEntry>("TorsionEntry")
.field("sugar_1", &TorsionEntry::sugar_1)
.field("sugar_2", &TorsionEntry::sugar_2)
.field("atom_number_1", &TorsionEntry::atom_number_1)
.field("atom_number_2", &TorsionEntry::atom_number_2)
.field("phi", &TorsionEntry::phi)
.field("psi", &TorsionEntry::psi);

register_vector<TorsionEntry>("vector<TorsionEntry>");


value_object<TableEntry>("TableEntry")
.field("svg", &TableEntry::svg)
Expand All @@ -320,10 +244,12 @@ EMSCRIPTEN_BINDINGS(privateer_module)
.field("anomer_err", &TableEntry::anomer_err)
.field("puckering_err", &TableEntry::puckering_err)
.field("chirality_err", &TableEntry::chirality_err)
.field("torsions", &TableEntry::torsions)
;

// .field("description", &TableEntry::description);

function("read_structure_to_table", &read_file_to_table);
register_vector<TableEntry>("Table");

}
9 changes: 6 additions & 3 deletions webserver/src/components/GlycanDetail/GlycanDetail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {lazy, useCallback, useEffect, useState} from "react";
import {MoorhenContainer, MoorhenContextProvider} from 'moorhen'
import GlycanDetailInfoBox from "./GlycanDetailInfoBox";
// import GlycanDetailTable from "./GlycanDetailTable";
import TorsionPlot from "../TorsionPlot/TorsionPlot";
// import TorsionPlot from "../TorsionPlot/TorsionPlot";
import TorsionMultiPlot from "../TorsionPlot/TorsionMultiPlot";

const GlycanDetailTable = lazy(() => import('./GlycanDetailTable'));

Expand Down Expand Up @@ -42,6 +43,7 @@ export default function GlycanDetail({tableData, hideMoorhen, setHideMoorhen, ro

const [width, setWidth] = useState(800);
const [height, setHeight] = useState(600);
const [torsionTab, setTorsionTab] = useState(0)

return (
<div className="flex-col justify-center items-center" style={{display: !hideMoorhen ? 'flex' : 'none'}}>
Expand All @@ -51,6 +53,7 @@ export default function GlycanDetail({tableData, hideMoorhen, setHideMoorhen, ro
<button onClick={() => {
setHideMoorhen(true);
window.scrollTo(0, scrollPosition);
setTorsionTab(0)
}}>
<span className="">&#8592; Back To Table</span>
</button>
Expand Down Expand Up @@ -82,9 +85,9 @@ export default function GlycanDetail({tableData, hideMoorhen, setHideMoorhen, ro

</MoorhenContextProvider>

{/* <h3 className="text-left text-xl w-full">Torsion Plots</h3>
<h3 className="text-left text-xl w-full">Torsion Plots</h3>

<TorsionPlot/> */}
<TorsionMultiPlot torsions={tableData[rowID].torsions} tab={torsionTab} setTab={setTorsionTab}/>

</div>);
}
80 changes: 80 additions & 0 deletions webserver/src/components/TorsionPlot/TorsionMultiPlot.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useEffect, useState } from "react";
import TorsionPlot from "./TorsionPlot";


function sortTorsions(torsions) {
const linkage_set = new Set();

torsions.map((torsion) => {
let linkage_string = ""
if (torsion.sugar_1 == "ASN") {
linkage_string = torsion.sugar_1 + "-" + torsion.atom_number_2 + "," + torsion.atom_number_1 + "-" + torsion.sugar_2
}
else {
linkage_string = torsion.sugar_2 + "-" + torsion.atom_number_2 + "," + torsion.atom_number_1 + "-" + torsion.sugar_1
}
linkage_set.add(linkage_string)
})

const linkage_array = Array.from(linkage_set)

const sorted_linkage_array = {}

linkage_array.map((item) => {
sorted_linkage_array[item] = []
})

torsions.map((torsion) => {
let linkage_string = ""
if (torsion.sugar_1 == "ASN") {
linkage_string = torsion.sugar_1 + "-" + torsion.atom_number_2 + "," + torsion.atom_number_1 + "-" + torsion.sugar_2
}
else {
linkage_string = torsion.sugar_2 + "-" + torsion.atom_number_2 + "," + torsion.atom_number_1 + "-" + torsion.sugar_1
}

sorted_linkage_array[linkage_string].push({"phi": torsion.phi, "psi": torsion.psi})
})

return [linkage_array, sorted_linkage_array]
}

function TorsionMultiPlotTabs({torsions, setTab}) {

const [linkage_array, sorted_linkage_array] = sortTorsions(torsions)

return (
linkage_array.map((item, index) => {
return (

<li class="mr-2">
<button class="inline-block p-4 border-b-2 border-transparent border-secondary rounded-t-lg hover:scale-105" onClick={() => {setTab(index)}}>{item}</button>
</li>

)
})
)
}

export default function TorsionMultiPlot({torsions, tab, setTab}) {


const [linkage_array, sorted_linkage_array] = sortTorsions(torsions)

useEffect(() => {
console.log(tab)
setTab(0)
}, [])

return (
<div className="flex flex-col align-middle justify-center items-center space-y-6 ">
<div class="text-sm font-medium text-center text-gray-500 border-gray-200 text-gray-400 border-gray-700">
<ul class="flex flex-wrap -mb-px">
<TorsionMultiPlotTabs torsions={torsions} setTab={setTab}/>
</ul>
</div>

<TorsionPlot linkage_type={linkage_array[tab]} sorted_torsion_list={sorted_linkage_array}/>
</div>
)
}
Loading

0 comments on commit 7fed532

Please sign in to comment.