UNPKG

vitessce

Version:

Vitessce app and React component library

191 lines (172 loc) 7.04 kB
import React, { useMemo } from 'react'; import { Component } from '../../app/constants'; import ScatterplotSubscriber, { SCATTERPLOT_DATA_TYPES, } from '../scatterplot/ScatterplotSubscriber'; import { capitalize } from '../../utils'; import { useLoaders, useCoordination, } from '../../app/state/hooks'; import { useReady, useUrls, } from '../hooks'; import { useCellsData, useExpressionMatrixData, } from '../data-hooks'; import { COMPONENT_COORDINATION_TYPES } from '../../app/state/coordination'; import GatingScatterplotOptions from './GatingScatterplotOptions'; import { getValueTransformFunction, VALUE_TRANSFORM_OPTIONS } from './utils'; /** * A subscriber component for the gating scatterplot. * @param {object} props * @param {number} props.uuid The unique identifier for this component. * @param {string} props.theme The current theme name. * @param {object} props.coordinationScopes The mapping from coordination types to coordination * scopes. * @param {boolean} props.disableTooltip Should the tooltip be disabled? * @param {function} props.removeGridComponent The callback function to pass to TitleInfo, * to call when the component has been removed from the grid. * @param {number} props.averageFillDensity Override the average fill density calculation * when using dynamic opacity mode. */ export default function GatingSubscriber(props) { const { coordinationScopes, observationsLabelOverride: observationsLabel = 'cell', } = props; // Get "props" from the coordination space. const [{ dataset, featureValueTransform, featureValueTransformCoefficient, gatingFeatureSelectionX, gatingFeatureSelectionY, }, { setFeatureValueTransform, setFeatureValueTransformCoefficient, setGatingFeatureSelectionX, setGatingFeatureSelectionY, }] = useCoordination( COMPONENT_COORDINATION_TYPES[Component.GATING], coordinationScopes, ); // Get data from loaders using the data hooks. const [urls, addUrl, resetUrls] = useUrls(); const loaders = useLoaders(); const [isReady, setItemIsReady, setItemIsNotReady, resetReadyItems] = useReady( SCATTERPLOT_DATA_TYPES, ); const [cells, cellsCount] = useCellsData(loaders, dataset, setItemIsReady, addUrl, true); const [expressionMatrix] = useExpressionMatrixData( loaders, dataset, setItemIsReady, addUrl, true, ); const transformOptions = VALUE_TRANSFORM_OPTIONS; const geneSelectOptions = expressionMatrix && expressionMatrix.cols ? expressionMatrix.cols : []; const mapping = (gatingFeatureSelectionX && gatingFeatureSelectionY ? `MAPPING_${gatingFeatureSelectionX}_${gatingFeatureSelectionY}` : null ); const title = useMemo( () => { if (!(gatingFeatureSelectionX && gatingFeatureSelectionY)) { return 'Gating'; } return `Gating (${gatingFeatureSelectionX} vs ${gatingFeatureSelectionY})`; }, [gatingFeatureSelectionX, gatingFeatureSelectionY], ); // Generate a new cells object with a mapping added for the user selected genes. const cellsWithGenes = useMemo( () => { if (!(gatingFeatureSelectionX && gatingFeatureSelectionY)) { return []; } // Get transform coefficient for log and arcsinh let coefficient = 1; const parsedTransformCoefficient = Number(featureValueTransformCoefficient); if (!Number.isNaN(parsedTransformCoefficient) && parsedTransformCoefficient > 0) { coefficient = parsedTransformCoefficient; } // Set transform function const transformFunction = getValueTransformFunction( featureValueTransform, coefficient, ); // Get the columns for the selected genes. const selectedGeneCols = [ expressionMatrix.cols.indexOf(gatingFeatureSelectionX), expressionMatrix.cols.indexOf(gatingFeatureSelectionY), ]; const updatedCells = {}; // Iterate through cells and build new cells with added mapping. expressionMatrix.rows.forEach((cellId, index) => { // Need to use new cell and cell.mappings objects // to prevent other views which use the same // top-level cells object reference from seeing any // modifications. const cellMatrixRowOffset = expressionMatrix.cols.length * index; updatedCells[cellId] = { ...cells[cellId], mappings: { ...cells[cellId].mappings, [mapping]: [ transformFunction(expressionMatrix.matrix[cellMatrixRowOffset + selectedGeneCols[0]]), transformFunction(expressionMatrix.matrix[cellMatrixRowOffset + selectedGeneCols[1]]), ], }, }; }); return updatedCells; }, [gatingFeatureSelectionX, gatingFeatureSelectionY, featureValueTransformCoefficient, featureValueTransform, expressionMatrix, cells, mapping], ); // Puts the mapping values in the cell info tooltip. const getCellInfoOverride = (cellId) => { const cell = cellsWithGenes[cellId]; const selectedTransformName = transformOptions.find( o => o.value === featureValueTransform, )?.name; const genePrefix = featureValueTransform ? `${selectedTransformName} ` : ''; const cellInfo = { [`${capitalize(observationsLabel)} ID`]: cellId }; if (gatingFeatureSelectionX && gatingFeatureSelectionY) { const [firstMapping, secondMapping] = cell.mappings[mapping]; cellInfo[genePrefix + gatingFeatureSelectionX] = firstMapping; cellInfo[genePrefix + gatingFeatureSelectionY] = secondMapping; } return cellInfo; }; let polygonCacheId = ''; if (featureValueTransform) polygonCacheId = `${featureValueTransform}_${featureValueTransformCoefficient}`; const customOptions = ( <GatingScatterplotOptions gatingFeatureSelectionX={gatingFeatureSelectionX} setGatingFeatureSelectionX={setGatingFeatureSelectionX} gatingFeatureSelectionY={gatingFeatureSelectionY} setGatingFeatureSelectionY={setGatingFeatureSelectionY} gatingFeatureValueTransform={featureValueTransform} setGatingFeatureValueTransform={setFeatureValueTransform} gatingFeatureValueTransformCoefficient={featureValueTransformCoefficient} setGatingFeatureValueTransformCoefficient={setFeatureValueTransformCoefficient} geneSelectOptions={geneSelectOptions} transformOptions={transformOptions} /> ); return ( <ScatterplotSubscriber {...props} loaders={loaders} cellsData={[cellsWithGenes, cellsCount]} useReadyData={[isReady, setItemIsReady, setItemIsNotReady, resetReadyItems]} urlsData={[urls, addUrl, resetUrls]} mapping={mapping} title={title} customOptions={customOptions} hideTools={!(gatingFeatureSelectionX && gatingFeatureSelectionY)} cellsEmptyMessage="Select two genes in the plot settings." getCellInfoOverride={getCellInfoOverride} cellSetsPolygonCacheId={polygonCacheId} /> ); }