diff --git a/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx b/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx
index 72303ef55..68ba67aa9 100644
--- a/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx
+++ b/apps/platform/src/components/AssociationsToolkit/components/Table/SectionRender.jsx
@@ -3,6 +3,7 @@ import { styled } from "@mui/material/styles";
import { LoadingBackdrop } from "ui";
import { ENTITIES } from "../../utils";
+import prioritisationColumns from "../../static_datasets/prioritisationColumns";
import targetSections from "../../../../sections/targetSections";
import evidenceSections from "../../../../sections/evidenceSections";
@@ -48,6 +49,7 @@ const getComponentConfig = (displayedTable, row, entity, id, section) => {
componentId: entity === ENTITIES.DISEASE ? row.id : id,
label: row.original.targetSymbol,
entityOfSection: "target",
+ componentProps: prioritisationColumns.find(el => el.id === section[0])?.sectionProps,
};
case "associations":
return {
@@ -61,6 +63,7 @@ const getComponentConfig = (displayedTable, row, entity, id, section) => {
name: row.original.diseaseName,
},
entityOfSection: "disease",
+ componentProps: {},
};
default:
return { Component: SectionNotFound };
@@ -87,13 +90,14 @@ export function SectionRender({
componentId,
label = row.original[entityToGet][nameProperty],
entityOfSection = entity,
+ componentProps,
} = getComponentConfig(displayedTable, row, entity, id, section);
if (!Component) return ;
return (
-
+
);
}
diff --git a/apps/platform/src/components/AssociationsToolkit/static_datasets/prioritisationColumns.ts b/apps/platform/src/components/AssociationsToolkit/static_datasets/prioritisationColumns.ts
index a6f36e34c..3d764c65f 100644
--- a/apps/platform/src/components/AssociationsToolkit/static_datasets/prioritisationColumns.ts
+++ b/apps/platform/src/components/AssociationsToolkit/static_datasets/prioritisationColumns.ts
@@ -61,6 +61,7 @@ const mouseOrthologMaxIdentityPercentage: Column = {
sectionId: "compGenomics",
description: "Mouse ortholog maximum identity percentage",
docsLink: "https://platform-docs.opentargets.org/target-prioritisation#mouse-ortholog-identity",
+ sectionProps: { viewMode: "mouseOrthologMaxIdentityPercentage" },
};
const hasHighQualityChemicalProbes: Column = {
@@ -124,6 +125,7 @@ const paralogMaxIdentityPercentage: Column = {
sectionId: "compGenomics",
description: "Paralog maximum identity percentage",
docsLink: "https://platform-docs.opentargets.org/target-prioritisation#paralogues",
+ sectionProps: { viewMode: "paralogMaxIdentityPercentage" },
};
const tissueSpecificity: Column = {
diff --git a/apps/platform/src/components/AssociationsToolkit/types.ts b/apps/platform/src/components/AssociationsToolkit/types.ts
index a12cc3dd0..a25b1f4f0 100644
--- a/apps/platform/src/components/AssociationsToolkit/types.ts
+++ b/apps/platform/src/components/AssociationsToolkit/types.ts
@@ -22,6 +22,7 @@ export type Column = {
docsLink: string;
weight?: number | undefined;
private?: boolean;
+ sectionProps?: any;
};
/***************
diff --git a/packages/sections/src/target/ComparativeGenomics/Body.jsx b/packages/sections/src/target/ComparativeGenomics/Body.jsx
index 6f0707fcd..fc42b1228 100644
--- a/packages/sections/src/target/ComparativeGenomics/Body.jsx
+++ b/packages/sections/src/target/ComparativeGenomics/Body.jsx
@@ -4,6 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faStar as faStarSolid } from "@fortawesome/free-solid-svg-icons";
import { faStar } from "@fortawesome/free-regular-svg-icons";
import { SectionItem, Link, Tooltip, OtTable } from "ui";
+import Visualisation from "./Visualisation";
import { definition } from ".";
import Description from "./Description";
@@ -24,6 +25,13 @@ import MouseIcon from "./MouseIcon";
import { identifiersOrgLink } from "../../utils/global";
import { decimalPlaces } from "../../constants";
+import { VIEW } from "ui/src/constants";
+
+const VIEW_MODES = {
+ default: "default",
+ mouseOrthologMaxIdentityPercentage: "mouseOrthologMaxIdentityPercentage",
+ paralogMaxIdentityPercentage: "paralogMaxIdentityPercentage",
+};
// map species ids to species icon component
const speciesIcons = {
@@ -126,7 +134,7 @@ function getColumns(classes) {
];
}
-function Body({ id: ensemblId, label: symbol, entity }) {
+function Body({ id: ensemblId, label: symbol, entity, viewMode = VIEW_MODES.default }) {
const classes = useStyles();
const variables = { ensemblId };
const request = useQuery(COMP_GENOMICS_QUERY, { variables });
@@ -136,7 +144,11 @@ function Body({ id: ensemblId, label: symbol, entity }) {
entity={entity}
definition={definition}
request={request}
+ defaultView={VIEW.chart}
renderDescription={() => }
+ renderChart={() => (
+
+ )}
renderBody={() => (
+ {viewMode !== "default" && (
+
+ {content[viewMode]}
+
+ Documentation
+
+
+ )}
+
+
+
+
+ );
+}
+
+const labels = {
+ 6239: "Caenorhabditis elegans (Nematode, N2)",
+ 7227: "Drosophila melanogaster (Fruit fly)",
+ 7955: "Zebrafish",
+ 8364: "Tropical clawed frog",
+ 9823: "Pig",
+ 9615: "Dog",
+ 10141: "Guinea Pig",
+ 9986: "Rabbit",
+ 10116: "Rat",
+ 10090: "Mouse",
+ 9544: "Macaque",
+ 9598: "Chimpanzee",
+ 9606: "Human",
+};
+
+function Visualisation({ homologues, width, viewMode }) {
+ const theme = useTheme();
+ const containerReference = useRef();
+ const height = 400;
+ const marginTop = 20;
+ const marginRight = 20;
+ const marginBottom = 30;
+ const marginLeft = 40;
+
+ // Declare the y (vertical position) scale.
+ const y = d3
+ .scalePoint()
+ .domain(yAxisValues)
+ .range([height - marginBottom * 2, marginTop]);
+
+ useEffect(() => {
+ const chartWidth = (width - marginRight) * 0.4;
+
+ // Declare the x (horizontal position) scale.
+ const queryScale = d3.scaleLinear().domain([0, 100]).range([marginLeft, chartWidth]);
+ const targetScale = d3
+ .scaleLinear()
+ .domain([100, 0])
+ .range([width - chartWidth, width - marginRight]);
+
+ // Create the SVG container.
+ const svg = d3.create("svg").attr("width", width).attr("height", height);
+
+ // Add the x-axis.
+ svg
+ .append("g")
+ .attr("transform", `translate(0,${height - marginBottom})`)
+ .call(d3.axisBottom(queryScale))
+ .call(g =>
+ g
+ .append("text")
+ .attr("x", marginLeft)
+ .attr("y", marginBottom - 1)
+ .attr("fill", "currentColor")
+ .attr("text-anchor", "start")
+ .text("Query Percentage Identity →")
+ );
+
+ // Add the x-axis.
+ svg
+ .append("g")
+ .attr("transform", `translate(0,${height - marginBottom})`)
+ .call(d3.axisBottom(targetScale))
+ .call(g =>
+ g
+ .append("text")
+ .attr("x", width - marginRight)
+ .attr("y", marginBottom - 1)
+ .attr("fill", "currentColor")
+ .attr("text-anchor", "end")
+ .text("← Target Percentage Identity")
+ );
+
+ const yAxis = d3
+ .axisLeft(y)
+ .tickFormat(d => labels[d])
+ .tickSize(0);
+ // Add the y-axis.
+ svg
+ .append("g")
+ .attr("class", "queryContainer")
+ .attr("transform", `translate(${width / 2},0)`)
+ .style("text-anchor", "middle")
+ .style("font-size", "0.85rem")
+ .style("font-weight", 400)
+ .call(yAxis)
+ .call(g => g.select(".domain").remove());
+
+ svg
+ .append("g")
+ .attr("stroke", "currentColor")
+ .attr("stroke-opacity", 0.1)
+ .call(g =>
+ g
+ .append("g")
+ .selectAll("line")
+ .data(queryScale.ticks())
+ .join("line")
+ .attr("x1", d => queryScale(d))
+ .attr("x2", d => queryScale(d))
+ .attr("y1", marginTop)
+ .attr("y2", height - marginBottom)
+ )
+ .call(g =>
+ g
+ .append("g")
+ .selectAll("line")
+ .data(targetScale.ticks())
+ .join("line")
+ .attr("x1", d => targetScale(d))
+ .attr("x2", d => targetScale(d))
+ .attr("y1", marginTop)
+ .attr("y2", height - marginBottom)
+ );
+
+ // Create the grid
+ const queryContainer = svg.append("g").attr("class", "queryContainer");
+ const targetContainer = svg.append("g").attr("class", "targetContainer");
+
+ queryContainer
+ .selectAll(".query")
+ .data(homologues)
+ .enter()
+ .append("circle")
+ .attr("cx", function (d) {
+ return queryScale(d.queryPercentageIdentity);
+ })
+ .attr("cy", function (d) {
+ return y(d.speciesId);
+ })
+ .attr("r", 6)
+ .attr("fill-opacity", 0.7)
+ .attr("fill", theme.palette.primary.main)
+ .attr("stroke", theme.palette.primary.dark);
+
+ targetContainer
+ .selectAll(".target")
+ .data(homologues)
+ .enter()
+ .append("circle")
+ .attr("cx", function (d) {
+ return targetScale(d.targetPercentageIdentity);
+ })
+ .attr("cy", function (d) {
+ return y(d.speciesId);
+ })
+ .attr("r", 6)
+ .attr("fill-opacity", 0.7)
+ .attr("fill", theme.palette.primary.main)
+ .attr("stroke", theme.palette.primary.dark);
+
+ if (viewMode === "mouseOrthologMaxIdentityPercentage") {
+ targetContainer.selectAll("circle").attr("fill", grey[300]).attr("stroke", grey[300]);
+
+ queryContainer
+ .selectAll("circle")
+ // .transition(300)
+ .attr("fill", d =>
+ d.queryPercentageIdentity > 80 && d.speciesId == "10090"
+ ? theme.palette.primary.main
+ : grey[300]
+ )
+ .attr("stroke", d =>
+ d.queryPercentageIdentity > 80 && d.speciesId == "10090"
+ ? theme.palette.primary.dark
+ : grey[300]
+ );
+ queryContainer
+ .append("line")
+ .attr("x1", queryScale(80))
+ .attr("x2", queryScale(80))
+ .attr("y1", marginTop)
+ .attr("y2", height - marginBottom)
+ .attr("stroke", "#2e5943");
+
+ svg
+ .selectAll(".queryContainer text")
+ .attr("color", d => (d === "10090" ? theme.palette.text.primary : grey[400]));
+ }
+ if (viewMode === "paralogMaxIdentityPercentage") {
+ queryContainer.selectAll("circle").attr("fill", grey[300]).attr("stroke", grey[300]);
+
+ targetContainer
+ .selectAll("circle")
+ // .transition(300)
+ .attr("fill", d =>
+ d.targetPercentageIdentity > 60 && d.speciesId == "9606"
+ ? theme.palette.primary.main
+ : grey[300]
+ )
+ .attr("stroke", d =>
+ d.targetPercentageIdentity > 60 && d.speciesId == "9606"
+ ? theme.palette.primary.dark
+ : grey[300]
+ );
+ targetContainer
+ .append("line")
+ .attr("x1", targetScale(60))
+ .attr("x2", targetScale(60))
+ .attr("y1", marginTop)
+ .attr("y2", height - marginBottom)
+ .attr("stroke", "#e3a772");
+
+ svg
+ .selectAll(".queryContainer text")
+ .attr("color", d => (d === "9606" ? theme.palette.text.primary : grey[400]));
+ }
+
+ // Append the SVG element.
+ containerReference.current.append(svg.node());
+ return () => svg.remove();
+ }, [homologues, width, viewMode]);
+
+ return ;
+}
+export default Wrapper;