Skip to content

Commit

Permalink
Changes from PyGenePlexus (#45)
Browse files Browse the repository at this point in the history
The items in here that changed are from commits 5722d9b, d07ce39 and
62cfc9a in the PyGenePlexus repo. Things that specifically changed that
might need a UI tweak here
- In both the probability and similarity tables there are columns from
z-scores and p-values
- The edge lists are now weighted again
- using Mondo instead of DisGeNet for disease-gene annotations
- In similarity table there is now a column called "Task" that describes
the type of GSC it is from
- changed how the auPRC values are returned, especially when they can't
be calculated
- Added a column "Gene Name" to the tables the show how the input IDs
are converted
- If training and showing results for different species, the probability
data frame now can have known-novel and Class-Label columns and this
information is based on one-to-one ortholog info. Can be used in network
figure.

Other UI ask that could be good in this PR is possibly showing only
StTRING as an option and then having a button a user clicks labeled
"More Options" that would show the BioGRID and IMP networks. Similarity
the GSC could be default to Combined and the user needs to click a
button to see the individual GSCs. This is #44

I also added a script to gather and zip the data for the function. I
uploaded the new data to the GCP bucket.

---------

Co-authored-by: Vincent Rubinetti <vince.rubinetti@gmail.com>
  • Loading branch information
ChristopherMancuso and vincerubinetti authored Sep 19, 2024
1 parent 9e2f9c8 commit 9e37586
Show file tree
Hide file tree
Showing 22 changed files with 322 additions and 170 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ __pycache__/
/.keys/*

data
functions/convert_ids/convert-ids_data.tar.gz
functions/ml/ml_data.tar.gz
50 changes: 33 additions & 17 deletions frontend/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,24 @@ export type Species =
export type Network = "BioGRID" | "STRING" | "IMP";

/** geneset context options */
export type GenesetContext = "GO" | "Monarch" | "DisGeNet" | "Combined";
export type GenesetContext = "GO" | "Monarch" | "Mondo" | "Combined";

/** convert-ids endpoint response format */
export type _ConvertIds = {
input_count: number;
convert_ids: string[];
table_summary: {
Network: string;
Network: Network;
NetworkGenes: number;
PositiveGenes: number;
}[];
df_convert_out: {
"Original ID": string;
"Entrez ID": string;
"Gene Name": string;
"In BioGRID?": string;
"In IMP?": string;
"In STRING?": string;
"Original ID": string;
}[];
};

Expand All @@ -55,9 +56,9 @@ export const convertConvertIds = (backend: _ConvertIds) => {
table: backend.df_convert_out.map((row) => ({
input: row["Original ID"],
entrez: row["Entrez ID"],
biogrid: row["In BioGRID?"] === "Y",
imp: row["In IMP?"] === "Y",
string: row["In STRING?"] === "Y",
name: row["Gene Name"],
inNetwork:
(row["In BioGRID?"] ?? row["In IMP?"] ?? row["In STRING?"]) === "Y",
})),
};
};
Expand Down Expand Up @@ -100,32 +101,38 @@ export const revertAnalysisInputs = (
/** convert-ids endpoint response format */
export type _AnalysisResults = {
df_convert_out_subset: {
"Original ID": string;
"Entrez ID": string;
"Gene Name": string;
"In BioGRID?"?: string;
"In IMP?"?: string;
"In STRING?"?: string;
"Original ID": string;
}[];
avgps: number[];
avgps: (number | null | undefined)[];
positive_genes: number;
isolated_genes: string[];
isolated_genes_sym: string[];
df_edge: { Node1: string; Node2: string }[];
df_edge_sym: { Node1: string; Node2: string }[];
df_edge: { Node1: string; Node2: string; Weight: number }[];
df_edge_sym: { Node1: string; Node2: string; Weight: number }[];
df_probs: {
Rank: number;
Entrez: string;
Symbol: string;
Name: string;
Probability: number;
"Known/Novel": "Known" | "Novel";
"Class-Label": "P" | "N" | "U";
Probability: number;
"Z-score": number;
"P-adjusted": number;
}[];
df_sim: {
Rank: number;
Task: string;
ID: string;
Name: string;
Similarity: number;
"Z-score": number;
"P-adjusted": number;
}[];
};

Expand All @@ -136,39 +143,48 @@ export const convertAnalysisResults = (backend: _AnalysisResults) => ({
entrez: row["Entrez ID"].match(/Could Not be mapped to Entrez/i)
? ""
: row["Entrez ID"],
name: row["Gene Name"],
inNetwork:
(row["In BioGRID?"] ?? row["In IMP?"] ?? row["In STRING?"]) === "Y",
})),
crossValidation: backend.avgps,
positiveGenes: backend.positive_genes,
predictions: backend.df_probs.map((row) => ({
rank: row.Rank,
entrez: row.Entrez,
symbol: row.Symbol,
name: row.Name,
probability: row.Probability,
knownNovel: row["Known/Novel"],
classLabel: expandClass(row["Class-Label"]),
probability: row.Probability,
zScore: row["Z-score"],
pAdjusted: row["P-adjusted"],
rank: row.Rank,
})),
similarities: backend.df_sim.map((row) => ({
rank: row.Rank,
task: row.Task,
id: row.ID,
name: row.Name,
similarity: row.Similarity,
zScore: row["Z-score"],
pAdjusted: row["P-adjusted"],
rank: row.Rank,
})),
network: {
nodes: backend.df_probs.map((row) => ({
rank: row.Rank,
probability: row.Probability,
entrez: row.Entrez,
symbol: row.Symbol,
name: row.Name,
knownNovel: row["Known/Novel"],
classLabel: expandClass(row["Class-Label"]),
probability: row.Probability,
zScore: row["Z-score"],
pAdjusted: row["P-adjusted"],
rank: row.Rank,
})),
links: backend.df_edge.map((row) => ({
edges: backend.df_edge.map((row) => ({
source: row.Node1,
target: row.Node2,
weight: row.Weight,
})),
},
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Heading.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ h4.heading {
}

.icon {
color: var(--deep-mid);
color: var(--deep);
}

.anchor {
Expand Down
15 changes: 10 additions & 5 deletions frontend/src/components/Radios.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ReactElement, ReactNode } from "react";
import { cloneElement, useEffect, useId, useState } from "react";
import { FaRegCircle, FaRegCircleDot } from "react-icons/fa6";
import { FaCircleDot, FaRegCircle } from "react-icons/fa6";
import clsx from "clsx";
import { usePrevious } from "@reactuses/core";
import Flex from "@/components/Flex";
Expand Down Expand Up @@ -110,16 +110,21 @@ const Radios = <O extends Option>({

{/* check mark */}
{selectedWFallback === option.id ? (
<FaRegCircleDot
className={clsx(classes.check, classes.selected)}
/>
<FaCircleDot className={clsx(classes.check, classes.checked)} />
) : (
<FaRegCircle className={classes.check} />
)}

{/* text content */}
<Flex direction="column" hAlign="left" gap="sm">
<span className="primary">{option.primary}</span>
<span
className={clsx(
"primary",
selectedWFallback === option.id && classes.checked,
)}
>
{option.primary}
</span>
{option.secondary && (
<span className="secondary">{option.secondary}</span>
)}
Expand Down
30 changes: 26 additions & 4 deletions frontend/src/components/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import Slider from "@/components/Slider";
import TextBox from "@/components/TextBox";
import Tooltip from "@/components/Tooltip";
import { downloadCsv } from "@/util/download";
import { formatNumber } from "@/util/string";
import { formatDate, formatNumber } from "@/util/string";
import classes from "./Table.module.css";

type Col<
Expand Down Expand Up @@ -69,7 +69,10 @@ type Col<
show?: boolean;
/** tooltip to show in header cell */
tooltip?: ReactNode;
/** custom render function for cell */
/**
* custom render function for cell. return undefined or null to fallback to
* default formatting.
*/
render?: (cell: NoInfer<Datum[Key]>) => ReactNode;
};

Expand Down Expand Up @@ -212,8 +215,13 @@ const Table = <Datum extends object>({ cols, rows }: Props<Datum>) => {
/** func to use for filtering individual column */
filterFn: filterFunc,
/** render func for cell */
cell: (cell) =>
col.render ? col.render(cell.getValue()) : cell.getValue(),
cell: (cell) => {
const raw = cell.getValue();
const rendered = col.render?.(raw);
return rendered === undefined || rendered === null
? defaultFormat(raw)
: rendered;
},
}),
);

Expand Down Expand Up @@ -633,3 +641,17 @@ const Filter = <Datum extends object>({ column, def }: FilterProps<Datum>) => {
/>
);
};

/** default cell formatter based on detected type */
const defaultFormat = (cell: unknown) => {
if (typeof cell === "number") return formatNumber(cell);
if (typeof cell === "boolean") return cell ? "True" : "False";
/** if falsey (except 0 and false) */
if (!cell) return "-";
if (Array.isArray(cell)) return cell.length.toLocaleString();
if (cell instanceof Date) return formatDate(cell);
if (typeof cell === "object")
return Object.keys(cell).length.toLocaleString();
if (typeof cell === "string") return cell;
return String(cell);
};
5 changes: 5 additions & 0 deletions frontend/src/global/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@
font-weight: var(--medium);
}

.mini-table > :nth-child(even):empty::after {
content: "-";
color: var(--gray);
}

/** automatically applied to all icons (react-icons and imported custom icons) */

.icon {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/global/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ hr {
/** text */

a {
color: var(--accent);
color: var(--deep);
transition: color var(--fast);
}

Expand All @@ -87,7 +87,7 @@ a:hover {
}

p a:visited {
color: var(--deep);
color: var(--accent);
}

p a:visited:hover {
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/global/theme.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
:root {
/* accent */
--accent: #ba3960;
--accent: hsl(342, 50%, 50%);
--accent-light: hsl(342, 100%, 90%);

/** deep */
--deep: #22577a;
--deep-mid: #5a92b7;
--deep-light: #ceebff;
--deep: hsl(204, 50%, 35%);
--deep-light: hsl(204, 100%, 90%);

/** grays */
--black: #000000;
Expand Down
26 changes: 7 additions & 19 deletions frontend/src/pages/NewAnalysis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ const genesetContextOptions: RadioOption<GenesetContext>[] = [
secondary: "Phenotypes",
},
{
id: "DisGeNet",
primary: "DisGeNet",
id: "Mondo",
primary: "Mondo",
secondary: "Diseases",
},
];
Expand Down Expand Up @@ -184,7 +184,7 @@ const NewAnalysisPage = () => {

/** restrict species options based on other params */
const filteredSpeciesOptions = speciesOptions.filter((option) => {
if (genesetContext === "DisGeNet" && option.id !== "Human") return false;
if (genesetContext === "Mondo" && option.id !== "Human") return false;
if (network === "BioGRID" && option.id === "Zebrafish") return false;
return true;
});
Expand All @@ -196,10 +196,10 @@ const NewAnalysisPage = () => {
)
toast("BioGRID does not support Zebrafish.", "warning", "warn1");
if (
genesetContext === "DisGeNet" &&
genesetContext === "Mondo" &&
(speciesTrain !== "Human" || speciesTest !== "Human")
)
toast("DisGeNet only supports Human genes.", "warning", "warn2");
toast("Mondo only supports Human genes.", "warning", "warn2");

/** auto-select species */
useEffect(() => {
Expand Down Expand Up @@ -386,20 +386,8 @@ const NewAnalysisPage = () => {
render: (cell) => cell || <Mark type="error">Failed</Mark>,
},
{
key: "biogrid",
name: "In BioGRID",
render: YesNo,
filterType: "boolean",
},
{
key: "imp",
name: "In IMP",
render: YesNo,
filterType: "boolean",
},
{
key: "string",
name: "In STRING",
key: "inNetwork",
name: "In Network",
render: YesNo,
filterType: "boolean",
},
Expand Down
40 changes: 13 additions & 27 deletions frontend/src/pages/Testbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import TextBox from "@/components/TextBox";
import Tile from "@/components/Tile";
import { toast } from "@/components/Toasts";
import Tooltip from "@/components/Tooltip";
import { themeVariables } from "@/util/dom";
import { formatDate, formatNumber } from "@/util/string";
import tableData from "../../fixtures/table.json";

Expand Down Expand Up @@ -78,33 +79,18 @@ const TestbedPage = () => {

{/* color palette */}
<Flex gap="none">
{[
"accent",
"deep",
"deep-mid",
"deep-light",
"black",
"off-black",
"dark-gray",
"gray",
"light-gray",
"off-white",
"white",
"success",
"warning",
"error",
].map((color, index) => (
<Tooltip key={index} content={color}>
<div
aria-hidden
style={{
width: 50,
height: 50,
background: `var(--${color})`,
}}
/>
</Tooltip>
))}
{Object.entries(themeVariables)
.filter(
([, value]) => value.startsWith("#") || value.startsWith("hsl"),
)
.map(([variable, color], index) => (
<Tooltip key={index} content={variable}>
<div
aria-hidden
style={{ width: 50, height: 50, background: color }}
/>
</Tooltip>
))}
</Flex>

<p>
Expand Down
Loading

0 comments on commit 9e37586

Please sign in to comment.