Skip to content

Commit

Permalink
ESCKAN-20 refactor - phenotype colors
Browse files Browse the repository at this point in the history
  • Loading branch information
D-GopalKrishna committed May 27, 2024
1 parent 04bfa25 commit a3d6878
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 46 deletions.
25 changes: 13 additions & 12 deletions src/components/Connections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useState } from "react";
import { Box, Chip, TextField, Typography } from "@mui/material";
import { ArrowRightIcon } from "./icons";
import { vars } from "../theme/variables";
import { HierarchicalItem, SubConnections, PhenotypeDetail, SummaryType, KsMapType } from "./common/Types";
import { HierarchicalItem, SubConnections, SummaryType, KsMapType, PhenotypeType } from "./common/Types";
import { useDataContext } from "../context/DataContext.ts";
import {
calculateSecondaryConnections,
Expand Down Expand Up @@ -58,34 +58,34 @@ function Connections() {
const viasStatement = convertViaToString(Object.values(viasConnection))
const totalConnectionCount = Object.keys(selectedConnectionSummary?.connections || {} as KsMapType).length;
const phenotypeNamesArray = useMemo(() => getAllPhenotypes(selectedConnectionSummary?.connections || {} as KsMapType), [selectedConnectionSummary]);
const [phenotypes, setPhenotypes] = useState<PhenotypeDetail[]>([]);
const [phenotypes, setPhenotypes] = useState<PhenotypeType>({});


useEffect(() => {
if (selectedConnectionSummary && phenotypeNamesArray && phenotypeNamesArray.length > 0) {
const phenotypeColors: string[] = generatePhenotypeColors(phenotypeNamesArray.length)
setPhenotypes(phenotypeNamesArray.map((phenotype, index) => ({
label: phenotype,
color: phenotypeColors[index],
ksId: ''
})))
const phenotypes: PhenotypeType = {};
phenotypeNamesArray.forEach((phenotype, index) => {
phenotypes[phenotype] = {
label: phenotype,
color: phenotypeColors[index],
}
})
setPhenotypes(phenotypes);
}
}, [phenotypeNamesArray, selectedConnectionSummary])

const nerves = getNerveFilters(viasConnection, majorNerves);


useEffect(() => {
if (selectedConnectionSummary && phenotypes) {
if (selectedConnectionSummary && phenotypes && selectedConnectionSummary.hierarchy && hierarchicalNodes) {
const destinations = Array.from(selectedConnectionSummary.endOrgan?.children?.values()).reduce((acc, organ, index) => {
acc[organ.id] = { ...organ, children: new Map<string, BaseEntity>(), order: index };
return acc;
}, {} as Record<string, Organ>);

const connections = calculateSecondaryConnections(
hierarchicalNodes, destinations, knowledgeStatements, summaryFilters, phenotypes,
selectedConnectionSummary.hierarchy
);
const connections = calculateSecondaryConnections(hierarchicalNodes, destinations, knowledgeStatements, summaryFilters, selectedConnectionSummary.hierarchy)
setConnectionsMap(connections);
}
}, [hierarchicalNodes, selectedConnectionSummary, summaryFilters, knowledgeStatements, phenotypes]);
Expand Down Expand Up @@ -193,6 +193,7 @@ function Connections() {
secondaryHeatmapData={heatmapData}
xAxisLabel={'Project to'}
yAxisLabel={'Somas in'}
phenotypes={phenotypes}
/>
</Box>

Expand Down
8 changes: 4 additions & 4 deletions src/components/SummaryFiltersDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo } from "react";
import { SummaryFilters, useDataContext } from "../context/DataContext";
import CustomFilterDropdown from "./common/CustomFilterDropdown";
import { Option, PhenotypeDetail } from "./common/Types";
import { Option, PhenotypeType } from "./common/Types";
import { Box } from "@mui/material";
import { searchNerveFilter, searchPhenotypeFilter } from "../services/searchService";
import { OTHER_PHENOTYPE_LABEL } from "../settings";
Expand All @@ -27,7 +27,7 @@ const filterConfig: FilterConfig[] = [

const SummaryFiltersDropdown = ({ nerves, phenotypes }: {
nerves: { [key: string]: string },
phenotypes: PhenotypeDetail[]
phenotypes: PhenotypeType
}) => {
const { summaryFilters, setSummaryFilters } = useDataContext();

Expand All @@ -39,9 +39,9 @@ const SummaryFiltersDropdown = ({ nerves, phenotypes }: {
content: []
}));
}
const convertPhenotypesToOptions = (phenotypes: PhenotypeDetail[]): Option[] => {
const convertPhenotypesToOptions = (phenotypes: PhenotypeType): Option[] => {
// filter the phenotype where label is other
return phenotypes.map(phenotype => ({
return Object.values(phenotypes).map(phenotype => ({
id: phenotype.label,
label: phenotype.label,
group: 'Phenotype',
Expand Down
23 changes: 18 additions & 5 deletions src/components/common/Heatmap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { vars } from "../../theme/variables";
import CollapsibleList from "./CollapsibleList";
import HeatMap from "react-heatmap-grid";
import HeatmapTooltip from "./HeatmapTooltip";
import { HierarchicalItem, SubConnections } from "./Types.ts";
import { HierarchicalItem, PhenotypeType, SubConnections } from "./Types.ts";
import { getNormalizedValueForMinMax } from "../../services/summaryHeatmapService.ts";
import { generateYLabelsAndIds, getPhenotypeColors } from "../../services/heatmapService.ts";
import { OTHER_PHENOTYPE_LABEL } from "../../settings.ts";


const { gray50, primaryPurple500, gray100A, gray500 } = vars;
Expand All @@ -21,6 +22,7 @@ interface HeatmapGridProps {
selectedCell?: { x: number, y: number } | null;
heatmapData?: number[][];
secondaryHeatmapData?: SubConnections[][];
phenotypes?: PhenotypeType;
}

const prepareSecondaryHeatmapData = (data?: SubConnections[][]): number[][] => {
Expand All @@ -32,7 +34,7 @@ const prepareSecondaryHeatmapData = (data?: SubConnections[][]): number[][] => {
const HeatmapGrid: FC<HeatmapGridProps> = ({
xAxis, yAxis, setYAxis,
xAxisLabel, yAxisLabel,
onCellClick, selectedCell, heatmapData, secondaryHeatmapData
onCellClick, selectedCell, heatmapData, secondaryHeatmapData, phenotypes
}) => {
const secondary = secondaryHeatmapData ? true : false;

Expand All @@ -58,7 +60,6 @@ const HeatmapGrid: FC<HeatmapGridProps> = ({
const yAxisData = generateYLabelsAndIds(yAxis);



const handleCellClick = (x: number, y: number) => {
const ids = yAxisData.ids
if (onCellClick) {
Expand All @@ -71,8 +72,20 @@ const HeatmapGrid: FC<HeatmapGridProps> = ({
_x: number,
_y: number
) => {
if (secondary && secondaryHeatmapData && secondaryHeatmapData[_y] && secondaryHeatmapData[_y][_x]) {
const phenotypeColors = secondaryHeatmapData[_y][_x]?.colors;
if (phenotypes && secondary && secondaryHeatmapData && secondaryHeatmapData[_y] && secondaryHeatmapData[_y][_x]) {
const matrixCellPhenotypes = secondaryHeatmapData[_y][_x]?.phenotypes;

const phenotypeColorsSet = new Set<string>();
matrixCellPhenotypes.forEach(phenotype => {
const phnColor = phenotypes[phenotype]?.color
if (phnColor) {
phenotypeColorsSet.add(phnColor);
} else {
phenotypeColorsSet.add(phenotypes[OTHER_PHENOTYPE_LABEL].color);
}
});

const phenotypeColors = Array.from(phenotypeColorsSet);
const phenotypeColor = getPhenotypeColors(normalizedValue, phenotypeColors);

return phenotypeColor ? phenotypeColor : `rgba(131, 0, 191, ${normalizedValue})`;
Expand Down
7 changes: 5 additions & 2 deletions src/components/common/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type Option = {
export type LabelIdPair = { labels: string[], ids: string[] };

export type KsMapType = Record<string, KnowledgeStatement>;
export type SubConnections = { colors: string[], ksIds: Set<string> };
export type SubConnections = { phenotypes: string[], ksIds: Set<string> };
export enum SummaryType {
Summary = 'summary',
DetailedSummary = 'detailedSummary',
Expand All @@ -37,5 +37,8 @@ export interface HierarchicalItem {
export type PhenotypeDetail = {
label: string;
color: string;
ksId: string;
};

export type PhenotypeType = {
[key: string]: PhenotypeDetail;
}
7 changes: 4 additions & 3 deletions src/components/connections/PhenotypeLegend.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Box, Typography } from "@mui/material"
import { PhenotypeDetail } from "../common/Types"
import { PhenotypeDetail, PhenotypeType } from "../common/Types"
import { vars } from "../../theme/variables";

const { gray100 } = vars;


const PhenotypeLegend = (
{ phenotypes }: { phenotypes: PhenotypeDetail[] }
{ phenotypes }: { phenotypes: PhenotypeType }
) => {
const phenotypesLegends = Object.values(phenotypes);
return (
<Box sx={{
position: 'sticky',
Expand All @@ -34,7 +35,7 @@ const PhenotypeLegend = (
alignItems: 'center',
gap: '1.5rem'
}}>
{phenotypes?.map((phenotype: PhenotypeDetail) => (
{phenotypesLegends?.map((phenotype: PhenotypeDetail) => (
<Box sx={{
p: '0.1875rem 0.25rem',
display: 'flex',
Expand Down
30 changes: 10 additions & 20 deletions src/services/summaryHeatmapService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { HierarchicalItem, SubConnections, KsMapType } from "../components/common/Types.ts";
import { SummaryFilters } from "../context/DataContext.ts";
import { HierarchicalNode, KnowledgeStatement, Organ } from "../models/explorer.ts";
import { PhenotypeDetail } from "../components/common/Types.ts";
import { FIXED_FOUR_PHENOTYPE_COLORS_ARRAY, OTHER_PHENOTYPE_LABEL } from "../settings.ts";


Expand Down Expand Up @@ -126,7 +125,7 @@ export function summaryFilterKnowledgeStatements(knowledgeStatements: Record<str
export function calculateSecondaryConnections(
hierarchicalNodes: Record<string, HierarchicalNode>, endorgans: Record<string, Organ>,
allKnowledgeStatements: Record<string, KnowledgeStatement>, summaryFilters: SummaryFilters,
phenotypes: PhenotypeDetail[], hierarchyNode: HierarchicalNode
hierarchyNode: HierarchicalNode
): Map<string, SubConnections[]> {

// Apply filters to organs and knowledge statements
Expand All @@ -147,12 +146,13 @@ export function calculateSecondaryConnections(
}

const node = hierarchicalNodes[nodeId];
const result: SubConnections[] = Object.values(endorgans).map(() => ({ colors: [], ksIds: new Set<string>() }));
const result: SubConnections[] = Object.values(endorgans).map(() => ({ phenotypes: [], ksIds: new Set<string>() }));

if (node.children && node.children.size > 0) {
node.children.forEach(childId => {
const childConnections = computeNodeConnections(childId);
childConnections.forEach((child, index) => {
result[index].colors = [...new Set([...result[index].colors, ...child.colors])];
result[index].phenotypes = [...new Set([...result[index].phenotypes, ...child.phenotypes])];
result[index].ksIds = new Set([...result[index].ksIds, ...child.ksIds]);
});
});
Expand All @@ -165,29 +165,19 @@ export function calculateSecondaryConnections(
const knowledgeStatementIds = Array.from(node.destinationDetails[endOrganIRI])
.filter(ksId => ksId in knowledgeStatements);

if (knowledgeStatementIds.length > 0) {
const ksPhenotypes = knowledgeStatementIds.map(ksId => knowledgeStatements[ksId].phenotype).filter(phenotype => phenotype !== '');
const phenotypeColorsSet = new Set<string>();

const unknownFilter = phenotypes.find(p => p.label === 'other');
ksPhenotypes.length === 0 ? phenotypeColorsSet.add(unknownFilter?.color || '') :
ksPhenotypes.map(phenotype => {
const phn = phenotypes.find(p => p.label === phenotype);
phn ? phenotypeColorsSet.add(phn.color) : phenotypeColorsSet.add(unknownFilter?.color || '') // FIXME: Could be a bug
})

const phenotypeColors = Array.from(phenotypeColorsSet)
result[index].colors = phenotypeColors
result[index].ksIds = new Set([...result[index].ksIds, ...knowledgeStatementIds]);
}
const ksPhenotypes = knowledgeStatementIds.map(ksId => {
return knowledgeStatements[ksId].phenotype ? knowledgeStatements[ksId].phenotype : OTHER_PHENOTYPE_LABEL
})

result[index].phenotypes = [...new Set(ksPhenotypes)];
result[index].ksIds = new Set([...result[index].ksIds, ...knowledgeStatementIds]);
}
});
}

memo.set(nodeId, result);
return result;
}

computeNodeConnections(hierarchyNode.id)
return memo;
}
Expand Down

0 comments on commit a3d6878

Please sign in to comment.