Skip to content

Commit 8205993

Browse files
authored
WGCNA upgrades (#1492)
* add link type for bipartite network visualization * change linktype to correlationdirection * add correlation direction to unipartite network * capitalize correlation direction options * improve naming * use isRight to avoid using underscore properties
1 parent dcb2ca4 commit 8205993

4 files changed

Lines changed: 158 additions & 66 deletions

File tree

packages/libs/eda/src/lib/core/api/DataClient/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
} from '../../types/general';
2626
import { VariableDescriptor, StringVariableValue } from '../../types/variable';
2727
import { ComputationAppOverview } from '../../types/visualization';
28+
import { NetworkCorrelationDirection } from '../../components/visualizations/implementations/NetworkVisualization';
2829

2930
export const AppsResponse = type({
3031
apps: array(ComputationAppOverview),
@@ -434,6 +435,7 @@ const NetworkConfig = partial({
434435
variables: unknown,
435436
correlationCoefThreshold: number,
436437
significanceThreshold: number,
438+
correlationDirection: NetworkCorrelationDirection,
437439
});
438440
export const NetworkResponse = type({
439441
network: type({
@@ -448,6 +450,7 @@ export interface NetworkRequestParams {
448450
config: {
449451
correlationCoefThreshold?: number;
450452
significanceThreshold?: number;
453+
correlationDirection?: NetworkCorrelationDirection;
451454
};
452455
}
453456

@@ -492,6 +495,9 @@ export const CorrelationBipartiteNetworkResponse = intersection([
492495
correlationCoefThreshold: number,
493496
significanceThreshold: number,
494497
}),
498+
partial({
499+
correlationDirection: NetworkCorrelationDirection,
500+
}),
495501
]);
496502

497503
export interface BipartiteNetworkRequestParams {
@@ -500,6 +506,7 @@ export interface BipartiteNetworkRequestParams {
500506
config: {
501507
correlationCoefThreshold?: number;
502508
significanceThreshold?: number;
509+
correlationDirection?: NetworkCorrelationDirection;
503510
};
504511
}
505512

packages/libs/eda/src/lib/core/components/computations/plugins/correlation.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useMemo } from 'react';
1+
import { useMemo } from 'react';
22
import {
33
CollectionVariableTreeNode,
44
VariableTreeNode,
@@ -36,7 +36,6 @@ import {
3636
CompleteCorrelationConfig,
3737
CorrelationConfig,
3838
} from '../../../types/apps';
39-
import { NodeData } from '@veupathdb/components/lib/types/plots/network';
4039

4140
const cx = makeClassNameHelper('AppStepConfigurationContainer');
4241

packages/libs/eda/src/lib/core/components/visualizations/implementations/BipartiteNetworkVisualization.tsx

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
import { twoColorPalette } from '@veupathdb/components/lib/types/plots/addOns';
2222
import { useCallback, useMemo } from 'react';
2323
import { scaleOrdinal } from 'd3-scale';
24-
import { uniq } from 'lodash';
24+
import { capitalize, uniq } from 'lodash';
2525
import { usePromise } from '../../../hooks/promise';
2626
import {
2727
useDataClient,
@@ -48,12 +48,16 @@ import {
4848
NodeData,
4949
NodeMenuAction,
5050
} from '@veupathdb/components/lib/types/plots/network';
51+
import RadioButtonGroup from '@veupathdb/components/lib/components/widgets/RadioButtonGroup';
52+
import { NetworkCorrelationDirection } from './NetworkVisualization';
53+
import { isRight } from 'fp-ts/lib/Either';
5154
// end imports
5255

5356
// Defaults
5457
const DEFAULT_CORRELATION_COEF_THRESHOLD = 0.5; // Ability for user to change this value not yet implemented.
5558
const DEFAULT_SIGNIFICANCE_THRESHOLD = 0.05; // Ability for user to change this value not yet implemented.
5659
const DEFAULT_LINK_COLOR_DATA = '0';
60+
const DEFAULT_LINK_TYPE = 'Both'; // Correlation direction. Applies to correlation networks only.
5761
const MIN_STROKE_WIDTH = 0.5; // Minimum stroke width for links in the network. Will represent the smallest link weight.
5862
const MAX_STROKE_WIDTH = 6; // Maximum stroke width for links in the network. Will represent the largest link weight.
5963
const DEFAULT_NUMBER_OF_LINE_LEGEND_ITEMS = 4;
@@ -75,6 +79,8 @@ function createDefaultConfig(): BipartiteNetworkConfig {
7579
return {
7680
correlationCoefThreshold: DEFAULT_CORRELATION_COEF_THRESHOLD,
7781
significanceThreshold: DEFAULT_SIGNIFICANCE_THRESHOLD,
82+
correlationDirection:
83+
DEFAULT_LINK_TYPE.toLowerCase() as NetworkCorrelationDirection,
7884
};
7985
}
8086

@@ -83,6 +89,7 @@ export type BipartiteNetworkConfig = t.TypeOf<typeof BipartiteNetworkConfig>;
8389
export const BipartiteNetworkConfig = t.partial({
8490
correlationCoefThreshold: t.number,
8591
significanceThreshold: t.number,
92+
correlationDirection: NetworkCorrelationDirection,
8693
});
8794

8895
export interface BipartiteNetworkOptions
@@ -156,6 +163,7 @@ function BipartiteNetworkViz(
156163
config: {
157164
correlationCoefThreshold: vizConfig.correlationCoefThreshold,
158165
significanceThreshold: vizConfig.significanceThreshold,
166+
correlationDirection: vizConfig.correlationDirection,
159167
},
160168
computeConfig: computationConfiguration,
161169
};
@@ -180,6 +188,7 @@ function BipartiteNetworkViz(
180188
visualization.descriptor.type,
181189
vizConfig.correlationCoefThreshold,
182190
vizConfig.significanceThreshold,
191+
vizConfig.correlationDirection,
183192
])
184193
);
185194

@@ -472,37 +481,67 @@ function BipartiteNetworkViz(
472481
return (
473482
<div style={{ display: 'flex', flexDirection: 'column' }}>
474483
{!hideInputsAndControls && (
475-
<LabelledGroup label="Link thresholds" alignChildrenHorizontally={true}>
476-
<NumberInput
477-
onValueChange={(newValue?: NumberOrDate) =>
478-
updateVizConfig({ correlationCoefThreshold: Number(newValue) })
479-
}
480-
label={'Absolute correlation coefficient'}
481-
minValue={0}
482-
maxValue={1}
483-
value={
484-
vizConfig.correlationCoefThreshold ??
485-
DEFAULT_CORRELATION_COEF_THRESHOLD
486-
}
487-
step={0.05}
488-
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
489-
/>
490-
491-
<NumberInput
492-
label="P-Value"
493-
onValueChange={(newValue?: NumberOrDate) =>
494-
updateVizConfig({ significanceThreshold: Number(newValue) })
495-
}
496-
minValue={0}
497-
maxValue={1}
498-
value={
499-
vizConfig.significanceThreshold ?? DEFAULT_SIGNIFICANCE_THRESHOLD
500-
}
501-
containerStyles={{ marginLeft: 10 }}
502-
step={0.001}
503-
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
504-
/>
505-
</LabelledGroup>
484+
<div style={{ display: 'flex', flexDirection: 'row', gap: 10 }}>
485+
<LabelledGroup
486+
label="Link thresholds"
487+
alignChildrenHorizontally={true}
488+
containerStyles={{ maxWidth: 420 }}
489+
>
490+
<NumberInput
491+
onValueChange={(newValue?: NumberOrDate) =>
492+
updateVizConfig({ correlationCoefThreshold: Number(newValue) })
493+
}
494+
label={'Absolute correlation coefficient'}
495+
minValue={0}
496+
maxValue={1}
497+
value={
498+
vizConfig.correlationCoefThreshold ??
499+
DEFAULT_CORRELATION_COEF_THRESHOLD
500+
}
501+
step={0.05}
502+
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
503+
/>
504+
505+
<NumberInput
506+
label="P-Value"
507+
onValueChange={(newValue?: NumberOrDate) =>
508+
updateVizConfig({ significanceThreshold: Number(newValue) })
509+
}
510+
minValue={0}
511+
maxValue={1}
512+
value={
513+
vizConfig.significanceThreshold ??
514+
DEFAULT_SIGNIFICANCE_THRESHOLD
515+
}
516+
containerStyles={{ marginLeft: 10 }}
517+
step={0.001}
518+
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
519+
/>
520+
</LabelledGroup>
521+
<LabelledGroup
522+
label="Correlation direction"
523+
alignChildrenHorizontally={true}
524+
>
525+
<RadioButtonGroup
526+
options={['Positive', 'Negative', 'Both']}
527+
selectedOption={
528+
capitalize(vizConfig.correlationDirection) ?? DEFAULT_LINK_TYPE
529+
}
530+
onOptionSelected={(value) => {
531+
const validatedValue = NetworkCorrelationDirection.decode(
532+
value.toLowerCase()
533+
);
534+
if (isRight(validatedValue)) {
535+
updateVizConfig({
536+
correlationDirection: validatedValue.right,
537+
});
538+
} else {
539+
console.error('Invalid link type');
540+
}
541+
}}
542+
/>
543+
</LabelledGroup>
544+
</div>
506545
)}
507546
<OutputEntityTitle subtitle={plotSubtitle} />
508547
<LayoutComponent

packages/libs/eda/src/lib/core/components/visualizations/implementations/NetworkVisualization.tsx

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
LegendOptions,
99
} from '../../layouts/types';
1010
import { RequestOptions } from '../options/types';
11+
import { isRight } from 'fp-ts/lib/Either';
1112

1213
// Network imports
1314
import NetworkPlot, {
@@ -21,7 +22,7 @@ import {
2122
import { twoColorPalette } from '@veupathdb/components/lib/types/plots/addOns';
2223
import { useCallback, useMemo, useState } from 'react';
2324
import { scaleOrdinal } from 'd3-scale';
24-
import { uniq } from 'lodash';
25+
import { capitalize, uniq } from 'lodash';
2526
import { usePromise } from '../../../hooks/promise';
2627
import {
2728
useDataClient,
@@ -48,11 +49,13 @@ import MultiSelect, {
4849
Option as NodeLabelProp,
4950
} from '@veupathdb/components/lib/components/plotControls/MultiSelect';
5051
import { ResetButtonCoreUI } from '../../ResetButton';
52+
import RadioButtonGroup from '@veupathdb/components/lib/components/widgets/RadioButtonGroup';
5153
// end imports
5254

5355
// Defaults
5456
const DEFAULT_CORRELATION_COEF_THRESHOLD = 0.5; // Ability for user to change this value not yet implemented.
5557
const DEFAULT_SIGNIFICANCE_THRESHOLD = 0.05; // Ability for user to change this value not yet implemented.
58+
const DEFAULT_LINK_TYPE = 'Both'; // Correlation direction. Applies to correlation networks only.
5659
const DEFAULT_LINK_COLOR_DATA = '0';
5760
const MIN_STROKE_WIDTH = 0.5; // Minimum stroke width for links in the network. Will represent the smallest link weight.
5861
const MAX_STROKE_WIDTH = 6; // Maximum stroke width for links in the network. Will represent the largest link weight.
@@ -76,14 +79,27 @@ function createDefaultConfig(): NetworkConfig {
7679
return {
7780
correlationCoefThreshold: DEFAULT_CORRELATION_COEF_THRESHOLD,
7881
significanceThreshold: DEFAULT_SIGNIFICANCE_THRESHOLD,
82+
correlationDirection:
83+
DEFAULT_LINK_TYPE.toLowerCase() as NetworkCorrelationDirection,
7984
};
8085
}
8186

87+
export const NetworkCorrelationDirection = t.union([
88+
t.literal('positive'),
89+
t.literal('negative'),
90+
t.literal('both'),
91+
]);
92+
// eslint-disable-next-line @typescript-eslint/no-redeclare
93+
export type NetworkCorrelationDirection = t.TypeOf<
94+
typeof NetworkCorrelationDirection
95+
>;
96+
8297
export type NetworkConfig = t.TypeOf<typeof NetworkConfig>;
8398
// eslint-disable-next-line @typescript-eslint/no-redeclare
8499
export const NetworkConfig = t.partial({
85100
correlationCoefThreshold: t.number,
86101
significanceThreshold: t.number,
102+
correlationDirection: NetworkCorrelationDirection,
87103
});
88104

89105
interface Options
@@ -139,6 +155,7 @@ function NetworkViz(props: VisualizationProps<Options>) {
139155
config: {
140156
correlationCoefThreshold: vizConfig.correlationCoefThreshold,
141157
significanceThreshold: vizConfig.significanceThreshold,
158+
correlationDirection: vizConfig.correlationDirection,
142159
},
143160
computeConfig: computationConfiguration,
144161
};
@@ -163,6 +180,7 @@ function NetworkViz(props: VisualizationProps<Options>) {
163180
visualization.descriptor.type,
164181
vizConfig.correlationCoefThreshold,
165182
vizConfig.significanceThreshold,
183+
vizConfig.correlationDirection,
166184
])
167185
);
168186

@@ -514,37 +532,66 @@ function NetworkViz(props: VisualizationProps<Options>) {
514532
return (
515533
<div style={{ display: 'flex', flexDirection: 'column' }}>
516534
{!hideInputsAndControls && (
517-
<LabelledGroup label="Link thresholds" alignChildrenHorizontally={true}>
518-
<NumberInput
519-
onValueChange={(newValue?: NumberOrDate) =>
520-
updateVizConfig({ correlationCoefThreshold: Number(newValue) })
521-
}
522-
label={'Absolute correlation coefficient'}
523-
minValue={0}
524-
maxValue={1}
525-
value={
526-
vizConfig.correlationCoefThreshold ??
527-
DEFAULT_CORRELATION_COEF_THRESHOLD
528-
}
529-
step={0.05}
530-
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
531-
/>
532-
533-
<NumberInput
534-
label="P-Value"
535-
onValueChange={(newValue?: NumberOrDate) =>
536-
updateVizConfig({ significanceThreshold: Number(newValue) })
537-
}
538-
minValue={0}
539-
maxValue={1}
540-
value={
541-
vizConfig.significanceThreshold ?? DEFAULT_SIGNIFICANCE_THRESHOLD
542-
}
543-
containerStyles={{ marginLeft: 10 }}
544-
step={0.001}
545-
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
546-
/>
547-
</LabelledGroup>
535+
<div style={{ display: 'flex', flexDirection: 'row', gap: 10 }}>
536+
<LabelledGroup
537+
label="Link thresholds"
538+
alignChildrenHorizontally={true}
539+
>
540+
<NumberInput
541+
onValueChange={(newValue?: NumberOrDate) =>
542+
updateVizConfig({ correlationCoefThreshold: Number(newValue) })
543+
}
544+
label={'Absolute correlation coefficient'}
545+
minValue={0}
546+
maxValue={1}
547+
value={
548+
vizConfig.correlationCoefThreshold ??
549+
DEFAULT_CORRELATION_COEF_THRESHOLD
550+
}
551+
step={0.05}
552+
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
553+
/>
554+
555+
<NumberInput
556+
label="P-Value"
557+
onValueChange={(newValue?: NumberOrDate) =>
558+
updateVizConfig({ significanceThreshold: Number(newValue) })
559+
}
560+
minValue={0}
561+
maxValue={1}
562+
value={
563+
vizConfig.significanceThreshold ??
564+
DEFAULT_SIGNIFICANCE_THRESHOLD
565+
}
566+
containerStyles={{ marginLeft: 10 }}
567+
step={0.001}
568+
applyWarningStyles={cleanedData && cleanedData.nodes.length === 0}
569+
/>
570+
</LabelledGroup>
571+
<LabelledGroup
572+
label="Correlation direction"
573+
alignChildrenHorizontally={true}
574+
>
575+
<RadioButtonGroup
576+
options={['Positive', 'Negative', 'Both']}
577+
selectedOption={
578+
capitalize(vizConfig.correlationDirection) ?? DEFAULT_LINK_TYPE
579+
}
580+
onOptionSelected={(value) => {
581+
const validatedValue = NetworkCorrelationDirection.decode(
582+
value.toLowerCase()
583+
);
584+
if (isRight(validatedValue)) {
585+
updateVizConfig({
586+
correlationDirection: validatedValue.right,
587+
});
588+
} else {
589+
console.error('Invalid link type');
590+
}
591+
}}
592+
/>
593+
</LabelledGroup>
594+
</div>
548595
)}
549596
<OutputEntityTitle subtitle={plotSubtitle} />
550597
<LayoutComponent

0 commit comments

Comments
 (0)