Skip to content

Commit

Permalink
[BIOMAGE-1104] Remove unneeded calls to cell clustering in qc data in…
Browse files Browse the repository at this point in the history
…teg and conf embed (#335)

* Remove unneeded calls to cell clustering in qc data integ and conf embed

* Clean up code and replace missing plot figure to show the user

* Rename data update to worker specific type

* Update clustering requests to work for all clients viewing the experiment

* Fix tests

Co-authored-by: ogibson <[email protected]>
  • Loading branch information
cosa65 and ogibson authored Jun 17, 2021
1 parent 4a882d7 commit f263f66
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`runCellSetsClustering action Dispatches all required actions to update cell sets clustering. 1`] = `
Object {
"type": "cellSets/clusteringUpdating",
}
`;

exports[`runCellSetsClustering action Dispatches all required actions to update cell sets clustering. 2`] = `undefined`;

exports[`runCellSetsClustering action Dispatches all required actions to update cell sets clustering. 3`] = `undefined`;

exports[`runCellSetsClustering action Dispatches error action when sendWord fails 1`] = `
Object {
"type": "cellSets/clusteringUpdating",
}
`;

exports[`runCellSetsClustering action Dispatches error action when sendWord fails 2`] = `
Object {
"payload": Object {
"error": undefined,
"experimentId": "1234",
},
"type": "cellSets/error",
}
`;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
import updateCellSetsClustering from '../../../../redux/actions/cellSets/updateCellSetsClustering';
import runCellSetsClustering from '../../../../redux/actions/cellSets/runCellSetsClustering';
import initialState from '../../../../redux/reducers/cellSets/initialState';
import { fetchCachedWork } from '../../../../utils/cacheRequest';
import sendWork from '../../../../utils/sendWork';

enableFetchMocks();
const mockStore = configureStore([thunk]);
jest.mock('localforage');
jest.mock('../../../../utils/cacheRequest');

jest.mock('../../../../utils/sendWork', () => ({
__esModule: true, // this property makes it work
default: jest.fn(),
}));

const startDate = '2021-01-01T00:00:00';

const backendStatusStore = {
backendStatus: { status: { pipeline: { startDate } } },
};

describe('updateCellSetsClustering action', () => {
describe('runCellSetsClustering action', () => {
const experimentId = '1234';

beforeEach(() => {
Expand All @@ -36,7 +41,7 @@ describe('updateCellSetsClustering action', () => {
cellSets: { loading: true, error: false },
experimentSettings: backendStatusStore,
});
store.dispatch(updateCellSetsClustering(experimentId));
store.dispatch(runCellSetsClustering(experimentId));
expect(store.getActions().length).toEqual(0);
});

Expand All @@ -45,7 +50,7 @@ describe('updateCellSetsClustering action', () => {
cellSets: { loading: false, error: true },
experimentSettings: backendStatusStore,
});
store.dispatch(updateCellSetsClustering(experimentId));
store.dispatch(runCellSetsClustering(experimentId));
expect(store.getActions().length).toEqual(0);
});

Expand All @@ -68,20 +73,14 @@ describe('updateCellSetsClustering action', () => {
experimentSettings: backendStatusStore,
});

fetchCachedWork.mockImplementation(() => {
const resolveWith = {
name: 'one', color: '#ff0000', cellIds: ['1', '2', '3'],
};

return new Promise((resolve) => resolve(resolveWith));
});

const flushPromises = () => new Promise(setImmediate);

store.dispatch(updateCellSetsClustering(experimentId, 0.5));
sendWork.mockImplementation(() => Promise.resolve());

store.dispatch(runCellSetsClustering(experimentId, 0.5));

expect(fetchCachedWork).toHaveBeenCalledTimes(1);
expect(fetchCachedWork).toHaveBeenCalledWith(experimentId, 30, {
expect(sendWork).toHaveBeenCalledTimes(1);
expect(sendWork).toHaveBeenCalledWith(experimentId, 30, {
name: 'ClusterCells',
cellSetName: 'Louvain clusters',
type: 'louvain',
Expand All @@ -102,25 +101,20 @@ describe('updateCellSetsClustering action', () => {
done();
});

it('Dispatches error action when the reset fails', async () => {
it('Dispatches error action when sendWord fails', async () => {
const store = mockStore({
cellSets: { ...initialState, loading: false },
experimentSettings: backendStatusStore,
});
fetchCachedWork.mockImplementation(() => {
const resolveWith = {
results: { error: 'The backend returned an error' },
};

return new Promise((resolve) => resolve(resolveWith));
});
sendWork.mockImplementation(() => Promise.reject());

const flushPromises = () => new Promise(setImmediate);

store.dispatch(updateCellSetsClustering(experimentId, 0.5));
store.dispatch(runCellSetsClustering(experimentId, 0.5));

expect(fetchCachedWork).toHaveBeenCalledTimes(1);
expect(fetchCachedWork).toHaveBeenCalledWith(experimentId, 30, {
expect(sendWork).toHaveBeenCalledTimes(1);
expect(sendWork).toHaveBeenCalledWith(experimentId, 30, {
name: 'ClusterCells',
cellSetName: 'Louvain clusters',
type: 'louvain',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
saveProcessingSettings,
} from '../../../redux/actions/experimentSettings';

import updateCellSetsClustering from '../../../redux/actions/cellSets/updateCellSetsClustering';
import runCellSetsClustering from '../../../redux/actions/cellSets/runCellSetsClustering';
import { loadEmbedding } from '../../../redux/actions/embedding';

import SliderWithInput from '../../SliderWithInput';
Expand Down Expand Up @@ -49,7 +49,7 @@ const CalculationConfig = (props) => {
const { louvain: louvainSettings } = data?.clusteringSettings.methodSettings || {};

const debouncedCellSetClustering = useCallback(
_.debounce((resolution) => dispatch(updateCellSetsClustering(experimentId, resolution)), 1500),
_.debounce((resolution) => dispatch(runCellSetsClustering(experimentId, resolution)), 1500),
[],
);

Expand Down Expand Up @@ -231,7 +231,8 @@ const CalculationConfig = (props) => {
The parameter is, in a sense, a guess about the number of close neighbors each cell has.
In most implementations, perplexity defaults to 30. This focuses the attention of t-SNE on preserving the
distances to its 30 nearest neighbors and puts virtually no weight on preserving distances to the remaining points.
The perplexity value has a complex effect on the resulting pictures.'>
The perplexity value has a complex effect on the resulting pictures.'
>
<QuestionCircleOutlined />
</Tooltip>
</Form.Item>
Expand All @@ -247,7 +248,8 @@ const CalculationConfig = (props) => {
onBlur={(e) => setLearningRate(e.target.value)}
/>
<Tooltip title='If the learning rate is too high, the data may look like a "ball" with any point approximately equidistant from its nearest neighbours.
If the learning rate is too low, most points may look compressed in a dense cloud with few outliers. usually in the range [10.0, 1000.0]'>
If the learning rate is too low, most points may look compressed in a dense cloud with few outliers. usually in the range [10.0, 1000.0]'
>
<QuestionCircleOutlined />
</Tooltip>
</Form.Item>
Expand Down Expand Up @@ -313,7 +315,6 @@ const CalculationConfig = (props) => {
<Option value='tsne'>t-SNE</Option>
</Select>


</Form.Item>
{changes.embeddingSettings.method === 'umap' && renderUMAPSettings()}
{changes.embeddingSettings.method === 'tsne' && renderTSNESettings()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {

import PlotStyling from '../../plots/styling/PlotStyling';
import { filterCells } from '../../../utils/plotSpecs/generateEmbeddingCategoricalSpec';
import { updateCellSetsClustering } from '../../../redux/actions/cellSets';
import { updateProcessingSettings } from '../../../redux/actions/experimentSettings';
import loadCellMeta from '../../../redux/actions/cellMeta';
import generateDataProcessingPlotUuid from '../../../utils/generateDataProcessingPlotUuid';
Expand All @@ -34,7 +33,11 @@ const ConfigureEmbedding = (props) => {
const [plot, setPlot] = useState(null);
const cellSets = useSelector((state) => state.cellSets);
const cellMeta = useSelector((state) => state.cellMeta);
const { selectedConfigureEmbeddingPlot: selectedPlot } = useSelector((state) => state.experimentSettings.processing.meta);

const { selectedConfigureEmbeddingPlot: selectedPlot } = useSelector(
(state) => state.experimentSettings.processing.meta,
);

const filterName = 'configureEmbedding';

const router = useRouter();
Expand All @@ -43,11 +46,6 @@ const ConfigureEmbedding = (props) => {
_.debounce((plotUuid) => dispatch(savePlotConfig(experimentId, plotUuid)), 2000), [],
);

const debouncedCellSetClustering = useCallback(
_.debounce((resolution) => dispatch(updateCellSetsClustering(experimentId, resolution)), 2000),
[],
);

const continuousEmbeddingPlots = ['mitochondrialContent', 'doubletScores'];

useEffect(() => {
Expand Down Expand Up @@ -286,18 +284,9 @@ const ConfigureEmbedding = (props) => {
&& !cellSets.error
&& !cellSets.updateCellSetsClustering
&& selectedConfig
&& plotData) {
&& plotData
) {
setPlot(plots[selectedPlot].plot(selectedConfig, plotData));
if (!selectedConfig.selectedCellSet) { return; }

const propertiesArray = Object.keys(cellSets.properties);
const cellSetClusteringLength = propertiesArray.filter(
(cellSet) => cellSet === selectedConfig.selectedCellSet,
).length;

if (!cellSetClusteringLength) {
debouncedCellSetClustering(0.5);
}
}
}, [selectedConfig, cellSets, plotData]);

Expand Down
31 changes: 8 additions & 23 deletions src/components/data-processing/DataIntegration/DataIntegration.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@ import React, {
} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {
Row, Col, Space, PageHeader, Collapse, Skeleton, Alert,
Row, Col, Space, PageHeader, Collapse, Alert,
} from 'antd';
import _ from 'lodash';
import PropTypes from 'prop-types';
import { useRouter } from 'next/router';

import CalculationConfig from './CalculationConfig';
import MiniPlot from '../../plots/MiniPlot';

import { updateCellSetsClustering } from '../../../redux/actions/cellSets';

import PlotStyling from '../../plots/styling/PlotStyling';

import MiniPlot from '../../plots/MiniPlot';
import EmptyPlot from '../../plots/helpers/EmptyPlot';

import {
updatePlotConfig,
loadPlotConfig,
Expand Down Expand Up @@ -45,11 +44,6 @@ const DataIntegration = (props) => {
_.debounce((plotUuid) => dispatch(savePlotConfig(experimentId, plotUuid)), 2000), [],
);

const debouncedCellSetClustering = useCallback(
_.debounce((resolution) => dispatch(updateCellSetsClustering(experimentId, resolution)), 2000),
[],
);

const plots = {
embedding: {
title: 'Sample embedding',
Expand Down Expand Up @@ -244,18 +238,9 @@ const DataIntegration = (props) => {
&& !cellSets.error
&& !cellSets.updateCellSetsClustering
&& selectedConfig
&& plotData) {
&& plotData
) {
setPlot(plots[selectedPlot].plot(selectedConfig, plotData, true));
if (!selectedConfig.selectedCellSet) { return; }

const propertiesArray = Object.keys(cellSets.properties);
const cellSetClusteringLength = propertiesArray.filter(
(cellSet) => cellSet === selectedConfig.selectedCellSet,
).length;

if (!cellSetClusteringLength) {
debouncedCellSetClustering(0.5);
}
}
}, [selectedConfig, cellSets, plotData, calculationConfig]);

Expand Down Expand Up @@ -308,7 +293,7 @@ const DataIntegration = (props) => {
if (!selectedConfig || disabledByConfigEmbedding) {
return (
<center>
<Skeleton.Image style={{ width: 400, height: 400 }} />
<EmptyPlot mini={false} style={{ width: 400, height: 400 }} />
</center>
);
}
Expand Down Expand Up @@ -348,7 +333,7 @@ const DataIntegration = (props) => {
{plotObj.blockedByConfigureEmbedding && !configureEmbeddingFinished.current
? (
<center>
<Skeleton.Image />
<EmptyPlot mini />
</center>
)
: (
Expand Down
2 changes: 2 additions & 0 deletions src/redux/actions/cellSets/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import createCellSet from './createCellSet';
import deleteCellSet from './deleteCellSet';
import runCellSetsClustering from './runCellSetsClustering';
import updateCellSetsClustering from './updateCellSetsClustering';

import loadCellSets from './loadCellSets';
Expand All @@ -13,6 +14,7 @@ import unhideAllCellSets from './unhideAllCellSets';
export {
createCellSet,
deleteCellSet,
runCellSetsClustering,
updateCellSetsClustering,
loadCellSets,
saveCellSets,
Expand Down
Loading

0 comments on commit f263f66

Please sign in to comment.