@vitessce/statistical-plots 3.5.6 → 3.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{deflate-70ede287.js → deflate-287e693d.js} +1 -1
- package/dist/{index-07a7a93a.js → index-1f1b6355.js} +881 -49
- package/dist/index.js +3 -2
- package/dist/{jpeg-00a52550.js → jpeg-1b2c1d25.js} +1 -1
- package/dist/{lerc-55c1ff7e.js → lerc-4f010cd7.js} +1 -1
- package/dist/{lzw-b906a3b9.js → lzw-e60fb582.js} +1 -1
- package/dist/{packbits-10b5f4aa.js → packbits-a8bfe098.js} +1 -1
- package/dist/{raw-9317b0fd.js → raw-01dff90e.js} +1 -1
- package/dist/{webimage-1c43145b.js → webimage-6b926ce3.js} +1 -1
- package/dist-tsc/CellSetExpressionPlot.d.ts.map +1 -1
- package/dist-tsc/CellSetExpressionPlot.js +2 -1
- package/dist-tsc/Treemap.d.ts +11 -0
- package/dist-tsc/Treemap.d.ts.map +1 -0
- package/dist-tsc/Treemap.js +164 -0
- package/dist-tsc/TreemapOptions.d.ts +2 -0
- package/dist-tsc/TreemapOptions.d.ts.map +1 -0
- package/dist-tsc/TreemapOptions.js +29 -0
- package/dist-tsc/TreemapSubscriber.d.ts +2 -0
- package/dist-tsc/TreemapSubscriber.d.ts.map +1 -0
- package/dist-tsc/TreemapSubscriber.js +102 -0
- package/dist-tsc/index.d.ts +1 -0
- package/dist-tsc/index.js +1 -0
- package/package.json +8 -7
- package/src/CellSetExpressionPlot.js +4 -1
- package/src/Treemap.js +217 -0
- package/src/TreemapOptions.js +90 -0
- package/src/TreemapSubscriber.js +261 -0
- package/src/index.js +1 -0
package/dist/index.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { c, C, b, a, e, D, d, E, F } from "./index-
|
1
|
+
import { c, C, b, a, e, D, d, E, F, T } from "./index-1f1b6355.js";
|
2
2
|
import "react";
|
3
3
|
import "@vitessce/vit-s";
|
4
4
|
import "react-dom";
|
@@ -11,5 +11,6 @@ export {
|
|
11
11
|
D as DotPlotSubscriber,
|
12
12
|
d as ExpressionHistogram,
|
13
13
|
E as ExpressionHistogramSubscriber,
|
14
|
-
F as FeatureBarPlotSubscriber
|
14
|
+
F as FeatureBarPlotSubscriber,
|
15
|
+
T as TreemapSubscriber
|
15
16
|
};
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { i as inflate_1 } from "./pako.esm-68f84e2a.js";
|
2
|
-
import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-
|
2
|
+
import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-1f1b6355.js";
|
3
3
|
import "react";
|
4
4
|
import "@vitessce/vit-s";
|
5
5
|
import "react-dom";
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"CellSetExpressionPlot.d.ts","sourceRoot":"","sources":["../src/CellSetExpressionPlot.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qDAjBG;IAAwB,IAAI,EAApB,MAAM,EAAE;IAEM,SAAS,EAAvB,MAAM;IACU,MAAM,EAAtB,MAAM,EAAE;IAEM,KAAK,EAAnB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,WAAW,EAAzB,MAAM;IAGQ,YAAY,EAA1B,MAAM;IAGa,yBAAyB,EAA5C,MAAM,GAAC,IAAI;CAErB,
|
1
|
+
{"version":3,"file":"CellSetExpressionPlot.d.ts","sourceRoot":"","sources":["../src/CellSetExpressionPlot.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qDAjBG;IAAwB,IAAI,EAApB,MAAM,EAAE;IAEM,SAAS,EAAvB,MAAM;IACU,MAAM,EAAtB,MAAM,EAAE;IAEM,KAAK,EAAnB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,WAAW,EAAzB,MAAM;IAGQ,YAAY,EAA1B,MAAM;IAGa,yBAAyB,EAA5C,MAAM,GAAC,IAAI;CAErB,eA0XA"}
|
@@ -89,7 +89,8 @@ export default function CellSetExpressionPlot(props) {
|
|
89
89
|
.range(
|
90
90
|
// TODO: check for full path equality here.
|
91
91
|
sampleSetNames
|
92
|
-
.map(name => sampleSetColor?.find(d => d.path.at(-1) === name)
|
92
|
+
.map(name => (sampleSetColor?.find(d => d.path.at(-1) === name)?.color
|
93
|
+
|| [125, 125, 125]))
|
93
94
|
.map(colorArrayToString));
|
94
95
|
}
|
95
96
|
// Remove outliers on a per-group basis.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* Renders a treemap plot using D3.
|
3
|
+
* References:
|
4
|
+
* - https://observablehq.com/@d3/treemap-component
|
5
|
+
* - https://observablehq.com/@d3/treemap-stratify
|
6
|
+
* - https://observablehq.com/@d3/json-treemap
|
7
|
+
* - https://observablehq.com/@d3/nested-treemap
|
8
|
+
* @returns
|
9
|
+
*/
|
10
|
+
export default function Treemap(props: any): JSX.Element;
|
11
|
+
//# sourceMappingURL=Treemap.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"Treemap.d.ts","sourceRoot":"","sources":["../src/Treemap.js"],"names":[],"mappings":"AAqCA;;;;;;;;GAQG;AACH,yDA0KC"}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
/* eslint-disable indent */
|
3
|
+
/* eslint-disable camelcase */
|
4
|
+
import React, { useMemo, useEffect, useRef } from 'react';
|
5
|
+
import { scaleOrdinal } from 'd3-scale';
|
6
|
+
import { select } from 'd3-selection';
|
7
|
+
import { treemap, treemapBinary, hierarchy as d3_hierarchy } from 'd3-hierarchy';
|
8
|
+
import { rollup as d3_rollup } from 'd3-array';
|
9
|
+
import { isEqual } from 'lodash-es';
|
10
|
+
import { colorArrayToString } from '@vitessce/sets-utils';
|
11
|
+
import { getDefaultColor, pluralize as plur } from '@vitessce/utils';
|
12
|
+
// Based on Observable's built-in DOM.uid function.
|
13
|
+
// This is intended to be used with SVG clipPaths
|
14
|
+
// which require a unique href value to reference
|
15
|
+
// other elements contained in the DOM.
|
16
|
+
function uidGenerator(prefix) {
|
17
|
+
let i = 0;
|
18
|
+
return () => {
|
19
|
+
i += 1;
|
20
|
+
return { id: `${prefix}-${i}`, href: `#${prefix}-${i}` };
|
21
|
+
};
|
22
|
+
}
|
23
|
+
// Create a d3-scale ordinal scale mapping set paths to color strings.
|
24
|
+
function getColorScale(setSelectionArr, setColorArr, theme) {
|
25
|
+
return scaleOrdinal()
|
26
|
+
.domain(setSelectionArr || [])
|
27
|
+
.range(setSelectionArr
|
28
|
+
?.map(setNamePath => (setColorArr?.find(d => isEqual(d.path, setNamePath))?.color
|
29
|
+
|| getDefaultColor(theme)))
|
30
|
+
?.map(colorArrayToString) || []);
|
31
|
+
}
|
32
|
+
/**
|
33
|
+
* Renders a treemap plot using D3.
|
34
|
+
* References:
|
35
|
+
* - https://observablehq.com/@d3/treemap-component
|
36
|
+
* - https://observablehq.com/@d3/treemap-stratify
|
37
|
+
* - https://observablehq.com/@d3/json-treemap
|
38
|
+
* - https://observablehq.com/@d3/nested-treemap
|
39
|
+
* @returns
|
40
|
+
*/
|
41
|
+
export default function Treemap(props) {
|
42
|
+
const { obsCounts, obsColorEncoding, hierarchyLevels, theme, width, height, obsType, sampleType, obsSetColor, sampleSetColor, obsSetSelection, sampleSetSelection, marginTop = 5, marginRight = 5, marginLeft = 80, marginBottom, } = props;
|
43
|
+
const hierarchyData = useMemo(() => {
|
44
|
+
// Support both sampleSet->obsSet and
|
45
|
+
// obsSet->sampleSet hierarchy modes
|
46
|
+
if (!obsCounts) {
|
47
|
+
return null;
|
48
|
+
}
|
49
|
+
let map;
|
50
|
+
if (isEqual(hierarchyLevels, ['sampleSet', 'obsSet'])) {
|
51
|
+
map = d3_rollup(obsCounts, D => D[0].value, d => d.sampleSetPath, d => d.obsSetPath);
|
52
|
+
}
|
53
|
+
else if (isEqual(hierarchyLevels, ['obsSet', 'sampleSet'])) {
|
54
|
+
map = d3_rollup(obsCounts, D => D[0].value, d => d.obsSetPath, d => d.sampleSetPath);
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
throw new Error('Unexpected levels value.');
|
58
|
+
}
|
59
|
+
return d3_hierarchy(map);
|
60
|
+
}, [obsCounts, hierarchyLevels]);
|
61
|
+
const [obsSetColorScale, sampleSetColorScale] = useMemo(() => [
|
62
|
+
getColorScale(obsSetSelection, obsSetColor, theme),
|
63
|
+
getColorScale(sampleSetSelection, sampleSetColor, theme),
|
64
|
+
], [obsSetSelection, sampleSetSelection, sampleSetColor, obsSetColor, theme]);
|
65
|
+
const treemapLeaves = useMemo(() => {
|
66
|
+
const treemapFunc = treemap()
|
67
|
+
.tile(treemapBinary)
|
68
|
+
.size([width, height])
|
69
|
+
.padding(1)
|
70
|
+
.round(true);
|
71
|
+
// When d3.hierarchy is passed a Map object,
|
72
|
+
// the nodes are represented like [key, value] tuples.
|
73
|
+
// So in `.sum` and `.sort` below,
|
74
|
+
// `d[1]` accesses the value (i.e., cell count).
|
75
|
+
// Reference: https://d3js.org/d3-hierarchy/hierarchy#hierarchy
|
76
|
+
const treemapLayout = treemapFunc(hierarchyData
|
77
|
+
.sum(d => d[1])
|
78
|
+
.sort((a, b) => b[1] - a[1]));
|
79
|
+
return treemapLayout.leaves();
|
80
|
+
}, [hierarchyData, width, height]);
|
81
|
+
const svgRef = useRef();
|
82
|
+
useEffect(() => {
|
83
|
+
const domElement = svgRef.current;
|
84
|
+
const svg = select(domElement);
|
85
|
+
svg.selectAll('g').remove();
|
86
|
+
svg
|
87
|
+
.attr('width', width)
|
88
|
+
.attr('height', height)
|
89
|
+
.attr('viewBox', [0, 0, width, height])
|
90
|
+
.attr('style', 'font: 10px sans-serif');
|
91
|
+
if (!treemapLeaves || !obsSetSelection || !sampleSetSelection) {
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
// Add a group for each leaf of the hierarchy.
|
95
|
+
const leaf = svg.selectAll('g')
|
96
|
+
.data(treemapLeaves)
|
97
|
+
.join('g')
|
98
|
+
.attr('transform', d => `translate(${d.x0},${d.y0})`);
|
99
|
+
// Append a tooltip.
|
100
|
+
leaf.append('title')
|
101
|
+
.text((d) => {
|
102
|
+
const cellCount = d.data?.[1];
|
103
|
+
const primaryPathString = JSON.stringify(d.data[0]);
|
104
|
+
const secondaryPathString = JSON.stringify(d.parent.data[0]);
|
105
|
+
return `${cellCount.toLocaleString()} ${plur(obsType, cellCount)} in ${primaryPathString} and ${secondaryPathString}`;
|
106
|
+
});
|
107
|
+
const getLeafUid = uidGenerator('leaf');
|
108
|
+
const getClipUid = uidGenerator('clip');
|
109
|
+
const colorScale = obsColorEncoding === 'sampleSetSelection'
|
110
|
+
? sampleSetColorScale
|
111
|
+
: obsSetColorScale;
|
112
|
+
const getPathForColoring = d => (
|
113
|
+
// eslint-disable-next-line no-nested-ternary
|
114
|
+
obsColorEncoding === 'sampleSetSelection'
|
115
|
+
? (hierarchyLevels[0] === 'obsSet' ? d.data?.[0] : d.parent?.data?.[0])
|
116
|
+
: (hierarchyLevels[0] === 'sampleSet' ? d.data?.[0] : d.parent?.data?.[0]));
|
117
|
+
// Append a color rectangle for each leaf.
|
118
|
+
leaf.append('rect')
|
119
|
+
.attr('id', (d) => {
|
120
|
+
// eslint-disable-next-line no-param-reassign
|
121
|
+
d.leafUid = getLeafUid();
|
122
|
+
return d.leafUid.id;
|
123
|
+
})
|
124
|
+
.attr('fill', d => colorScale(getPathForColoring(d)))
|
125
|
+
.attr('fill-opacity', 0.8)
|
126
|
+
.attr('width', d => d.x1 - d.x0)
|
127
|
+
.attr('height', d => d.y1 - d.y0);
|
128
|
+
// Append a clipPath to ensure text does not overflow.
|
129
|
+
leaf.append('clipPath')
|
130
|
+
.attr('id', (d) => {
|
131
|
+
// eslint-disable-next-line no-param-reassign
|
132
|
+
d.clipUid = getClipUid();
|
133
|
+
return d.clipUid.id;
|
134
|
+
})
|
135
|
+
.append('use')
|
136
|
+
.attr('xlink:href', d => d.leafUid.href);
|
137
|
+
// Append multiline text.
|
138
|
+
leaf.append('text')
|
139
|
+
.attr('clip-path', d => `url(${d.clipUid.href})`)
|
140
|
+
.selectAll('tspan')
|
141
|
+
.data(d => ([
|
142
|
+
// Each element in this array corresponds to a line of text.
|
143
|
+
d.data?.[0]?.at(-1),
|
144
|
+
d.parent?.data?.[0]?.at(-1),
|
145
|
+
`${d.data?.[1].toLocaleString()} ${plur(obsType, d.data?.[1])}`,
|
146
|
+
]))
|
147
|
+
.join('tspan')
|
148
|
+
.attr('x', 3)
|
149
|
+
// eslint-disable-next-line no-unused-vars
|
150
|
+
.attr('y', (d, i, nodes) => `${(i === nodes.length - 1) * 0.3 + 1.1 + i * 0.9}em`)
|
151
|
+
.text(d => d);
|
152
|
+
}, [width, height, marginLeft, marginBottom, theme, marginTop, marginRight,
|
153
|
+
obsType, sampleType, treemapLeaves, sampleSetColor, sampleSetSelection,
|
154
|
+
obsSetSelection, obsSetColor, obsSetColorScale, sampleSetColorScale,
|
155
|
+
obsColorEncoding, hierarchyLevels,
|
156
|
+
]);
|
157
|
+
return (_jsx("svg", { ref: svgRef, style: {
|
158
|
+
top: 0,
|
159
|
+
left: 0,
|
160
|
+
width: `${width}px`,
|
161
|
+
height: `${height}px`,
|
162
|
+
position: 'relative',
|
163
|
+
} }));
|
164
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"TreemapOptions.d.ts","sourceRoot":"","sources":["../src/TreemapOptions.js"],"names":[],"mappings":"AASA,gEAgFC"}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import React from 'react';
|
3
|
+
import { useId } from 'react-aria';
|
4
|
+
import { isEqual } from 'lodash-es';
|
5
|
+
import { TableCell, TableRow } from '@material-ui/core';
|
6
|
+
import { capitalize } from '@vitessce/utils';
|
7
|
+
import { usePlotOptionsStyles, OptionSelect, OptionsContainer, } from '@vitessce/vit-s';
|
8
|
+
export default function TreemapOptions(props) {
|
9
|
+
const { children, obsType, sampleType, hierarchyLevels, setHierarchyLevels, obsColorEncoding, setObsColorEncoding, } = props;
|
10
|
+
const treemapOptionsId = useId();
|
11
|
+
const classes = usePlotOptionsStyles();
|
12
|
+
function handleColorEncodingChange(event) {
|
13
|
+
setObsColorEncoding(event.target.value);
|
14
|
+
}
|
15
|
+
function handleHierarchyLevelsOrderingChange(event) {
|
16
|
+
if (event.target.value === 'sampleSet') {
|
17
|
+
setHierarchyLevels(['sampleSet', 'obsSet']);
|
18
|
+
}
|
19
|
+
else {
|
20
|
+
setHierarchyLevels(['obsSet', 'sampleSet']);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
const primaryHierarchyLevel = isEqual(hierarchyLevels, ['sampleSet', 'obsSet']) ? 'sampleSet' : 'obsSet';
|
24
|
+
return (_jsxs(OptionsContainer, { children: [children, _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsx("label", { htmlFor: `cell-color-encoding-select-${treemapOptionsId}`, children: "Color Encoding" }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsxs(OptionSelect, { className: classes.select, value: obsColorEncoding, onChange: handleColorEncodingChange, inputProps: {
|
25
|
+
id: `cell-color-encoding-select-${treemapOptionsId}`,
|
26
|
+
}, children: [_jsxs("option", { value: "cellSetSelection", children: [capitalize(obsType), " Sets"] }), _jsxs("option", { value: "sampleSetSelection", children: [capitalize(sampleType), " Sets"] })] }) })] }), _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsx("label", { htmlFor: `treemap-set-hierarchy-levels-${treemapOptionsId}`, children: "Primary Hierarchy Level" }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsxs(OptionSelect, { className: classes.select, value: primaryHierarchyLevel, onChange: handleHierarchyLevelsOrderingChange, inputProps: {
|
27
|
+
id: `hierarchy-level-select-${treemapOptionsId}`,
|
28
|
+
}, children: [_jsxs("option", { value: "obsSet", children: [capitalize(obsType), " Sets"] }), _jsxs("option", { value: "sampleSet", children: [capitalize(sampleType), " Sets"] })] }) })] })] }));
|
29
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"TreemapSubscriber.d.ts","sourceRoot":"","sources":["../src/TreemapSubscriber.js"],"names":[],"mappings":"AAyBA,2DA2OC"}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
/* eslint-disable no-unused-vars */
|
3
|
+
import React, { useMemo } from 'react';
|
4
|
+
import { TitleInfo, useCoordination, useLoaders, useUrls, useReady, useGridItemSize, useObsFeatureMatrixIndices, useObsSetsData, useSampleEdgesData, useSampleSetsData, } from '@vitessce/vit-s';
|
5
|
+
import { ViewType, COMPONENT_COORDINATION_TYPES, ViewHelpMapping } from '@vitessce/constants-internal';
|
6
|
+
import { treeToSelectedSetMap, treeToSetSizesBySetNames, mergeObsSets } from '@vitessce/sets-utils';
|
7
|
+
import { pluralize as plur, commaNumber, unnestMap, capitalize } from '@vitessce/utils';
|
8
|
+
import { InternMap } from 'internmap';
|
9
|
+
import { isEqual } from 'lodash-es';
|
10
|
+
import Treemap from './Treemap.js';
|
11
|
+
import { useStyles } from './styles.js';
|
12
|
+
import TreemapOptions from './TreemapOptions.js';
|
13
|
+
const DEFAULT_HIERARCHY_LEVELS = ['obsSet', 'sampleSet'];
|
14
|
+
export function TreemapSubscriber(props) {
|
15
|
+
const { coordinationScopes, removeGridComponent, theme, helpText = ViewHelpMapping.TREEMAP, } = props;
|
16
|
+
const classes = useStyles();
|
17
|
+
const loaders = useLoaders();
|
18
|
+
// Get "props" from the coordination space.
|
19
|
+
const [{ dataset, obsType, featureType, featureValueType, obsFilter, obsHighlight, obsSetSelection, obsSetFilter, obsSelection, obsSelectionMode, obsSetHighlight, obsSetColor, obsColorEncoding, additionalObsSets, sampleType, sampleSetSelection, sampleSetFilter, sampleSetColor, sampleSelection, sampleSelectionMode, sampleFilter, sampleFilterMode, sampleHighlight, hierarchyLevels, }, { setObsFilter, setObsSelection, setObsSetFilter, setObsSetSelection, setObsSelectionMode, setObsFilterMode, setObsHighlight, setObsSetColor, setObsColorEncoding, setAdditionalObsSets, setSampleFilter, setSampleSetFilter, setSampleFilterMode, setSampleSelection, setSampleSetSelection, setSampleSelectionMode, setSampleHighlight, setSampleSetColor, setHierarchyLevels, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.TREEMAP], coordinationScopes);
|
20
|
+
const [width, height, containerRef] = useGridItemSize();
|
21
|
+
// TODO: how to deal with multimodal cases (multiple obsIndex, one per modality)?
|
22
|
+
const [{ obsIndex }, matrixIndicesStatus, matrixIndicesUrls] = useObsFeatureMatrixIndices(loaders, dataset, false, { obsType, featureType, featureValueType });
|
23
|
+
const [{ obsSets }, obsSetsStatus, obsSetsUrls] = useObsSetsData(loaders, dataset, true, {}, {}, { obsType });
|
24
|
+
const [{ sampleIndex, sampleSets }, sampleSetsStatus, sampleSetsUrls] = useSampleSetsData(loaders, dataset,
|
25
|
+
// TODO: support `false`, i.e., configurations in which
|
26
|
+
// there are no sampleSets
|
27
|
+
true, { setSampleSetColor }, { sampleSetColor }, { sampleType });
|
28
|
+
const [{ sampleEdges }, sampleEdgesStatus, sampleEdgesUrls] = useSampleEdgesData(loaders, dataset,
|
29
|
+
// TODO: support `false`, i.e., configurations in which
|
30
|
+
// there are no sampleEdges
|
31
|
+
true, {}, {}, { obsType, sampleType });
|
32
|
+
const isReady = useReady([
|
33
|
+
matrixIndicesStatus,
|
34
|
+
obsSetsStatus,
|
35
|
+
sampleSetsStatus,
|
36
|
+
sampleEdgesStatus,
|
37
|
+
]);
|
38
|
+
const urls = useUrls([
|
39
|
+
matrixIndicesUrls,
|
40
|
+
obsSetsUrls,
|
41
|
+
sampleSetsUrls,
|
42
|
+
sampleEdgesUrls,
|
43
|
+
]);
|
44
|
+
const mergedObsSets = useMemo(() => mergeObsSets(obsSets, additionalObsSets), [obsSets, additionalObsSets]);
|
45
|
+
const mergedSampleSets = useMemo(() => mergeObsSets(sampleSets, null), [sampleSets]);
|
46
|
+
const obsCount = obsIndex?.length || 0;
|
47
|
+
const sampleCount = sampleIndex?.length || 0;
|
48
|
+
// TODO: use obsFilter / sampleFilter to display
|
49
|
+
// _all_ cells/samples in gray / transparent in background,
|
50
|
+
// and use obsSetSelection/sampleSetSelection to display
|
51
|
+
// the _selected_ samples in color in the foreground.
|
52
|
+
const [obsCounts, sampleCounts] = useMemo(() => {
|
53
|
+
const obsResult = new InternMap([], JSON.stringify);
|
54
|
+
const sampleResult = new InternMap([], JSON.stringify);
|
55
|
+
const hasSampleSetSelection = (Array.isArray(sampleSetSelection)
|
56
|
+
&& sampleSetSelection.length > 0);
|
57
|
+
const hasCellSetSelection = (Array.isArray(obsSetSelection)
|
58
|
+
&& obsSetSelection.length > 0);
|
59
|
+
const sampleSetKeys = hasSampleSetSelection ? sampleSetSelection : [null];
|
60
|
+
const cellSetKeys = hasCellSetSelection ? obsSetSelection : [null];
|
61
|
+
// First level: cell set
|
62
|
+
cellSetKeys.forEach((cellSetKey) => {
|
63
|
+
obsResult.set(cellSetKey, new InternMap([], JSON.stringify));
|
64
|
+
// Second level: sample set
|
65
|
+
sampleSetKeys.forEach((sampleSetKey) => {
|
66
|
+
obsResult.get(cellSetKey).set(sampleSetKey, 0);
|
67
|
+
});
|
68
|
+
});
|
69
|
+
const sampleSetSizes = treeToSetSizesBySetNames(mergedSampleSets, sampleSetSelection, sampleSetSelection, sampleSetColor, theme);
|
70
|
+
sampleSetKeys.forEach((sampleSetKey) => {
|
71
|
+
const sampleSetSize = sampleSetSizes.find(d => isEqual(d.setNamePath, sampleSetKey))?.size;
|
72
|
+
sampleResult.set(sampleSetKey, sampleSetSize || 0);
|
73
|
+
});
|
74
|
+
if (mergedObsSets && obsSetSelection) {
|
75
|
+
const sampleIdToSetMap = sampleSets && sampleSetSelection
|
76
|
+
? treeToSelectedSetMap(sampleSets, sampleSetSelection)
|
77
|
+
: null;
|
78
|
+
const cellIdToSetMap = treeToSelectedSetMap(mergedObsSets, obsSetSelection);
|
79
|
+
for (let i = 0; i < obsIndex.length; i += 1) {
|
80
|
+
const obsId = obsIndex[i];
|
81
|
+
const cellSet = cellIdToSetMap?.get(obsId);
|
82
|
+
const sampleId = sampleEdges?.get(obsId);
|
83
|
+
const sampleSet = sampleId ? sampleIdToSetMap?.get(sampleId) : null;
|
84
|
+
if (hasSampleSetSelection && !sampleSet) {
|
85
|
+
// Skip this sample if it is not in the selected sample set.
|
86
|
+
// eslint-disable-next-line no-continue
|
87
|
+
continue;
|
88
|
+
}
|
89
|
+
const prevObsCount = obsResult.get(cellSet)?.get(sampleSet);
|
90
|
+
obsResult.get(cellSet)?.set(sampleSet, prevObsCount + 1);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
return [
|
94
|
+
unnestMap(obsResult, ['obsSetPath', 'sampleSetPath', 'value']),
|
95
|
+
unnestMap(sampleResult, ['sampleSetPath', 'value']),
|
96
|
+
];
|
97
|
+
}, [obsIndex, sampleEdges, sampleSets, obsSetColor,
|
98
|
+
sampleSetColor, mergedObsSets, obsSetSelection, mergedSampleSets,
|
99
|
+
// TODO: consider filtering-related coordination values
|
100
|
+
]);
|
101
|
+
return (_jsx(TitleInfo, { title: `Treemap of ${capitalize(plur(obsType, 2))}`, info: `${commaNumber(obsCount)} ${plur(obsType, obsCount)} from ${commaNumber(sampleCount)} ${plur(sampleType, sampleCount)}`, removeGridComponent: removeGridComponent, urls: urls, theme: theme, isReady: isReady, helpText: helpText, options: (_jsx(TreemapOptions, { obsType: obsType, sampleType: sampleType, obsColorEncoding: obsColorEncoding, setObsColorEncoding: setObsColorEncoding, hierarchyLevels: hierarchyLevels || DEFAULT_HIERARCHY_LEVELS, setHierarchyLevels: setHierarchyLevels })), children: _jsx("div", { ref: containerRef, className: classes.vegaContainer, children: _jsx(Treemap, { obsCounts: obsCounts, sampleCounts: sampleCounts, obsColorEncoding: obsColorEncoding, hierarchyLevels: hierarchyLevels || DEFAULT_HIERARCHY_LEVELS, theme: theme, width: width, height: height, obsType: obsType, sampleType: sampleType, obsSetColor: obsSetColor, sampleSetColor: sampleSetColor, obsSetSelection: obsSetSelection, sampleSetSelection: sampleSetSelection }) }) }));
|
102
|
+
}
|
package/dist-tsc/index.d.ts
CHANGED
@@ -3,6 +3,7 @@ export { CellSetSizesPlotSubscriber } from "./CellSetSizesPlotSubscriber.js";
|
|
3
3
|
export { ExpressionHistogramSubscriber } from "./ExpressionHistogramSubscriber.js";
|
4
4
|
export { DotPlotSubscriber } from "./DotPlotSubscriber.js";
|
5
5
|
export { FeatureBarPlotSubscriber } from "./FeatureBarPlotSubscriber.js";
|
6
|
+
export { TreemapSubscriber } from "./TreemapSubscriber.js";
|
6
7
|
export { default as CellSetSizesPlot } from "./CellSetSizesPlot.js";
|
7
8
|
export { default as CellSetExpressionPlot } from "./CellSetExpressionPlot.js";
|
8
9
|
export { default as ExpressionHistogram } from "./ExpressionHistogram.js";
|
package/dist-tsc/index.js
CHANGED
@@ -3,6 +3,7 @@ export { CellSetSizesPlotSubscriber } from './CellSetSizesPlotSubscriber.js';
|
|
3
3
|
export { ExpressionHistogramSubscriber } from './ExpressionHistogramSubscriber.js';
|
4
4
|
export { DotPlotSubscriber } from './DotPlotSubscriber.js';
|
5
5
|
export { FeatureBarPlotSubscriber } from './FeatureBarPlotSubscriber.js';
|
6
|
+
export { TreemapSubscriber } from './TreemapSubscriber.js';
|
6
7
|
export { default as CellSetSizesPlot } from './CellSetSizesPlot.js';
|
7
8
|
export { default as CellSetExpressionPlot } from './CellSetExpressionPlot.js';
|
8
9
|
export { default as ExpressionHistogram } from './ExpressionHistogram.js';
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitessce/statistical-plots",
|
3
|
-
"version": "3.5.
|
3
|
+
"version": "3.5.7",
|
4
4
|
"author": "HIDIVE Lab at HMS",
|
5
5
|
"homepage": "http://vitessce.io",
|
6
6
|
"repository": {
|
@@ -23,17 +23,18 @@
|
|
23
23
|
"d3-axis": "^3.0.0",
|
24
24
|
"d3-selection": "^3.0.0",
|
25
25
|
"d3-format": "^3.1.0",
|
26
|
+
"d3-hierarchy": "^3.1.2",
|
26
27
|
"vega-scale": "^6.0.0",
|
27
28
|
"lodash-es": "^4.17.21",
|
28
29
|
"react-aria": "^3.28.0",
|
29
30
|
"internmap": "^2.0.3",
|
30
31
|
"uuid": "^9.0.0",
|
31
|
-
"@vitessce/constants-internal": "3.5.
|
32
|
-
"@vitessce/sets-utils": "3.5.
|
33
|
-
"@vitessce/utils": "3.5.
|
34
|
-
"@vitessce/vega": "3.5.
|
35
|
-
"@vitessce/vit-s": "3.5.
|
36
|
-
"@vitessce/gl": "3.5.
|
32
|
+
"@vitessce/constants-internal": "3.5.7",
|
33
|
+
"@vitessce/sets-utils": "3.5.7",
|
34
|
+
"@vitessce/utils": "3.5.7",
|
35
|
+
"@vitessce/vega": "3.5.7",
|
36
|
+
"@vitessce/vit-s": "3.5.7",
|
37
|
+
"@vitessce/gl": "3.5.7"
|
37
38
|
},
|
38
39
|
"devDependencies": {
|
39
40
|
"react": "^18.0.0",
|
@@ -124,7 +124,10 @@ export default function CellSetExpressionPlot(props) {
|
|
124
124
|
.range(
|
125
125
|
// TODO: check for full path equality here.
|
126
126
|
sampleSetNames
|
127
|
-
.map(name =>
|
127
|
+
.map(name => (
|
128
|
+
sampleSetColor?.find(d => d.path.at(-1) === name)?.color
|
129
|
+
|| [125, 125, 125]
|
130
|
+
))
|
128
131
|
.map(colorArrayToString),
|
129
132
|
);
|
130
133
|
}
|