Skip to content

Commit 752497f

Browse files
authored
Merge pull request #101 from Reed-CompBio/stats
Implement basic stats panel and fixed pathfinding gds calls
2 parents dbb6fd7 + e677d4d commit 752497f

File tree

10 files changed

+288
-87
lines changed

10 files changed

+288
-87
lines changed

client/src/components/Footer.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import { FaGithub } from "react-icons/fa";
33
import { BiSolidMessageAltError } from "react-icons/bi";
44
import { IconContext } from "react-icons";
55
import { Link } from "react-router-dom";
6+
import { MdOutlineMenuBook } from "react-icons/md";
7+
68

79
export default function Footer() {
810
const githubLink = "https://github.com/Reed-CompBio/protein-weaver/";
911
const githubIssuesLink = "https://github.com/Reed-CompBio/protein-weaver/issues/";
12+
const githuPagesDoc = "https://reed-compbio.github.io/protein-weaver/"
1013

1114
return (
1215
<div className="footer-container">
@@ -33,6 +36,11 @@ export default function Footer() {
3336
<a href={githubIssuesLink} target="_blank" rel="noopener noreferrer">
3437
<BiSolidMessageAltError className="footer-icon" />
3538
</a>
39+
<p> | </p>
40+
{/* GitHub Issues */}
41+
<a href={githuPagesDoc} target="_blank" rel="noopener noreferrer">
42+
<MdOutlineMenuBook className="footer-icon" />
43+
</a>
3644
</IconContext.Provider>
3745
</footer>
3846
</div>

client/src/components/Query.jsx

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ import CytoscapeComponent from "react-cytoscapejs";
1212
import cytoscape from "cytoscape";
1313
import { cytoscapeStyle, layout } from "../assets/CytoscapeConfig";
1414
import cola from "cytoscape-cola";
15-
// import {
16-
// cytoscapeTestElements,
17-
// cytoscapeTest,
18-
// cytoscapeTest2,
19-
// } from "../assets/CytoscapeTestElements";
2015

2116
// component imports
2217
import QueryError from "./QueryError";
@@ -30,6 +25,7 @@ import StatisticsTab from "./StatisticsTab";
3025

3126
// panel imports
3227
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
28+
import { fetchAvgDegree, getBasicStatistics } from "../tools/Statistics";
3329

3430
export default function Query() {
3531
const [query, setQuery] = useState({
@@ -67,6 +63,13 @@ export default function Query() {
6763
const [activeModeButton, setActiveModeButton] = useState("");
6864
const [dataParsingStatus, setDataParsingStatus] = useState(false);
6965
const [errorMessage, setErrorMessage] = useState("");
66+
const [rawData, setRawData] = useState("");
67+
const [networkStatistics, setNetworkStatistics] = useState({
68+
nodeCount: null,
69+
edgeCount: null,
70+
pathCount: null,
71+
avgNodeDegree: null,
72+
});
7073

7174
const [pageState, setPageState] = useState(0);
7275
cytoscape.use(cola);
@@ -176,6 +179,31 @@ export default function Query() {
176179
}
177180
}, [networkResult]);
178181

182+
//Once the network parsing has completed, get all the stats information of the subnetwork.
183+
useEffect(() => {
184+
if (dataParsingStatus) {
185+
//asyc function to get the average degree of subnetwork
186+
const getAvgDegree = async () => {
187+
try {
188+
const avgNodeDegree = await fetchAvgDegree(
189+
networkResult,
190+
query.species
191+
);
192+
setNetworkStatistics((prevState) => ({
193+
...prevState,
194+
avgNodeDegree: avgNodeDegree.toFixed(1),
195+
}));
196+
} catch (error) {
197+
return Promise.reject(
198+
new Error(`${response.status} ${response.statusText}`)
199+
);
200+
}
201+
};
202+
setNetworkStatistics(getBasicStatistics(networkResult, rawData, query));
203+
getAvgDegree();
204+
}
205+
}, [dataParsingStatus]);
206+
179207
// Function for submitting the query
180208
async function handleSubmit(e) {
181209
setSidebarNode(null);
@@ -197,6 +225,7 @@ export default function Query() {
197225
// get the k shortest paths for the query
198226
e.preventDefault();
199227
let network = null;
228+
let rawData = null;
200229
if (query.mode == "path") {
201230
try {
202231
network = await fetch("/api/getQuery", {
@@ -220,6 +249,7 @@ export default function Query() {
220249
}
221250
})
222251
.then((data) => {
252+
rawData = data;
223253
return NetworkParserPath(data, query.protein, query.goTerm);
224254
});
225255
} catch (error) {
@@ -253,6 +283,7 @@ export default function Query() {
253283
}
254284
})
255285
.then((data) => {
286+
rawData = data;
256287
return NetworkParserNode(data, query.protein, query.k);
257288
});
258289
} catch (error) {
@@ -261,11 +292,9 @@ export default function Query() {
261292
setHasError(true);
262293
setPageState(0);
263294
setIsLoading(false);
264-
265295
return;
266296
}
267297
}
268-
269298
// get induced subgraph
270299
if (network != null) {
271300
let nodeList = { nodeList: network.nodeList };
@@ -293,6 +322,7 @@ export default function Query() {
293322
})
294323
.then((edgeData) => {
295324
setNetworkResult(EdgeDataParser(network, edgeData));
325+
setRawData(rawData);
296326
setDataParsingStatus(true);
297327
return EdgeDataParser(network, edgeData);
298328
});
@@ -715,7 +745,9 @@ export default function Query() {
715745
</Panel>
716746
<PanelResizeHandle className="panel-resize-handle" />
717747
<Panel defaultSize={40} minSize={10}>
718-
<StatisticsTab></StatisticsTab>
748+
<StatisticsTab
749+
networkStatistics={networkStatistics}
750+
></StatisticsTab>
719751
</Panel>
720752
</PanelGroup>
721753
</Panel>

client/src/components/StatisticsTab.jsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,27 @@ import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
33
import { MdConstruction } from "react-icons/md";
44
import { Tooltip as ReactTooltip } from "react-tooltip";
55

6-
export default function StatisticsTab() {
6+
export default function StatisticsTab({ networkStatistics }) {
77
const [tabIndex, setTabIndex] = useState(0);
88

99
return (
1010
<div className="statistics-panel-container">
11-
{/* <h4 className="stats-title">Statistics</h4> */}
1211
<Tabs
1312
selectedIndex={tabIndex}
1413
onSelect={(index) => setTabIndex(index)}
1514
className="stats-tabs"
1615
selectedTabClassName="stats-tab-selected"
1716
>
1817
<TabList className="stats-tab-list">
19-
<Tab className="stats-tab">
20-
Graph
21-
<MdConstruction
22-
data-tooltip-id="construction-tooltip"
23-
className="construction"
24-
/>
25-
</Tab>
26-
<Tab className="stats-tab">
18+
<Tab className="stats-tab">Graph</Tab>
19+
<Tab className="stats-tab-construction" disabled={true}>
2720
Nodes
2821
<MdConstruction
2922
data-tooltip-id="construction-tooltip"
3023
className="construction"
3124
/>
3225
</Tab>{" "}
33-
<Tab className="stats-tab">
26+
<Tab className="stats-tab-construction" disabled={true}>
3427
Edges
3528
<MdConstruction
3629
data-tooltip-id="construction-tooltip"
@@ -39,13 +32,31 @@ export default function StatisticsTab() {
3932
</Tab>
4033
</TabList>
4134
<TabPanel>
42-
<h2>Statistics about graph</h2>
35+
<h4 className="stats-title">Graph stats</h4>
36+
<div className="graph-statistics-container">
37+
<div>
38+
<ul className="right-aligned-list">
39+
<li># of nodes:</li>
40+
<li># of edges:</li>
41+
<li># of paths from source:</li>
42+
<li>Average node degree:</li>
43+
</ul>
44+
</div>
45+
<div>
46+
<ul className="statistics-list">
47+
<li>{networkStatistics.nodeCount}</li>
48+
<li>{networkStatistics.edgeCount}</li>
49+
<li>{networkStatistics.pathCount}</li>
50+
<li>{networkStatistics.avgNodeDegree}</li>
51+
</ul>
52+
</div>
53+
</div>
4354
</TabPanel>
4455
<TabPanel>
45-
<h2>Statistics about nodes</h2>
56+
<h4 className="stats-title" >Node stats</h4>
4657
</TabPanel>
4758
<TabPanel>
48-
<h2>Statistics about edges</h2>
59+
<h4 className="stats-title" >Edges stats</h4>
4960
</TabPanel>
5061
</Tabs>
5162
<ReactTooltip

client/src/index.css

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,6 @@ p {
675675
height: 50px;
676676
}
677677

678-
679678
.bug-report {
680679
margin-left: 10px;
681680
align-self: center;
@@ -723,7 +722,7 @@ select {
723722
.footer-container {
724723
position: relative;
725724
bottom: 0;
726-
width: 100%
725+
width: 100%;
727726
}
728727

729728
.footer {
@@ -1420,6 +1419,7 @@ select {
14201419
margin: 0;
14211420
/* Remove margins */
14221421
display: flex;
1422+
cursor: pointer;
14231423
}
14241424

14251425
.stats-tab {
@@ -1430,26 +1430,27 @@ select {
14301430
background-color: #828588;
14311431
}
14321432

1433-
.stats-tab:hover {
1433+
.stats-tab-construction {
1434+
width: 100%;
1435+
padding: 5px;
1436+
text-align: center;
1437+
background-color: #828588;
1438+
}
1439+
1440+
.stats-tab:hover,
1441+
.stats-tab-construction:hover {
14341442
cursor: pointer;
1443+
pointer-events: none;
14351444
}
14361445

14371446
.stats-tab-selected {
1438-
/* border-bottom: 0px solid #828588;
1439-
border-right: 1px solid #828588;
1440-
border-top: 1px solid #828588;
1441-
border-left: 1px solid #828588; */
14421447
border-top-left-radius: 5px;
14431448
border-top-right-radius: 5px;
14441449
text-decoration: underline;
14451450
background-color: white;
14461451
}
14471452

14481453
.stats-tab-selected {
1449-
/* border-bottom: 0px solid #828588;
1450-
border-right: 1px solid #828588;
1451-
border-top: 1px solid #828588;
1452-
border-left: 1px solid #828588; */
14531454
border-top-left-radius: 5px;
14541455
border-top-right-radius: 5px;
14551456
text-decoration: underline;
@@ -1462,7 +1463,22 @@ select {
14621463
}
14631464

14641465
.stats-title {
1465-
margin-left: 16px;
1466-
margin-top: 16px;
1467-
margin-bottom: 10px;
1466+
text-align: left;
1467+
}
1468+
1469+
.graph-statistics-container {
1470+
display: flex;
1471+
margin: auto;
1472+
width: 90%;
1473+
justify-content: center;
1474+
}
1475+
1476+
.statistics-list {
1477+
list-style: none;
1478+
padding-left: 15px;
1479+
}
1480+
1481+
.right-aligned-list {
1482+
list-style: none;
1483+
text-align: right;
14681484
}

client/src/tools/Statistics.jsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
export function getBasicStatistics(network, rawData, query) {
2+
let networkStatistics = {
3+
nodeCount: null,
4+
edgeCount: null,
5+
pathCount: null,
6+
avgNodeDegree: null,
7+
};
8+
networkStatistics.nodeCount = network.nodeList.length - 1;
9+
networkStatistics.edgeCount = network.edgeList.length;
10+
11+
networkStatistics.pathCount = getPathCount(rawData, query.k, query.mode);
12+
return networkStatistics;
13+
}
14+
15+
export function getPathCount(data, k, mode) {
16+
if (mode == "path") {
17+
return data.length;
18+
} else return Math.min(k, data.length - 1);
19+
}
20+
21+
export async function fetchAvgDegree(network, species) {
22+
let nodeList = network.nodeList.slice(0, network.nodeList.length - 1);
23+
const requestBody = Object.assign(
24+
{ nodeList: nodeList },
25+
{
26+
species: species,
27+
}
28+
);
29+
try {
30+
const response = await fetch("/api/getAvgDegree", {
31+
method: "POST", // Specify the HTTP method
32+
headers: {
33+
"Content-Type": "application/json", // Set the Content-Type header for JSON data
34+
},
35+
body: JSON.stringify(requestBody), // Convert the request body to JSON string
36+
});
37+
38+
if (!response.ok) {
39+
throw new Error("Failed to fetch data");
40+
}
41+
let data = await response.json();
42+
data = data[0]._fields[0];
43+
return data;
44+
} catch (error) {
45+
console.error("Error fetching data:", error);
46+
throw error;
47+
}
48+
}

scripts/CallGraphProjection.cypher

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
CALL gds.graph.project('proGoGraph',['go_term', 'protein'],['ProGo', 'ProPro']);
1+
CALL gds.graph.project('proGoGraph',['go_term', 'protein'],['ProGo', 'ProPro']);
2+
CALL gds.graph.relationships.toUndirected( 'proGoGraph', {relationshipType: 'ProPro', mutateRelationshipType: 'ProProUndirected'} ) YIELD inputRelationships, relationshipsWritten;

0 commit comments

Comments
 (0)