From af0d1f6fb2999af07ab973e0a7ee3a67b7f02d0e Mon Sep 17 00:00:00 2001 From: Bruce Martin Date: Thu, 29 Nov 2018 16:33:21 -0800 Subject: [PATCH] issue #480 workaround (#484) * only load annotation var names * remove incorrect usage of var annotation data * temporary workaround for issue #480 * lint * issue warnings only once per item --- client/src/actions/index.js | 2 +- client/src/components/geneExpression/index.js | 4 +- server/app/scanpy_engine/scanpy_engine.py | 51 +++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/client/src/actions/index.js b/client/src/actions/index.js index f8b2d554..35b0281a 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -24,7 +24,7 @@ const doInitialDataLoad = () => "config", "schema", "annotations/obs", - "annotations/var", + "annotations/var?annotation-name=name", "layout/obs" ]) .map(r => `${globals.API.prefix}${globals.API.version}${r}`) diff --git a/client/src/components/geneExpression/index.js b/client/src/components/geneExpression/index.js index 3a3a378d..5d2e550f 100644 --- a/client/src/components/geneExpression/index.js +++ b/client/src/components/geneExpression/index.js @@ -27,7 +27,9 @@ const renderGene = (fuzzySortResult, { handleClick, modifiers, query }) => { { /* this fires when user clicks a menu item */ diff --git a/server/app/scanpy_engine/scanpy_engine.py b/server/app/scanpy_engine/scanpy_engine.py index 6a33b007..6090dfa3 100644 --- a/server/app/scanpy_engine/scanpy_engine.py +++ b/server/app/scanpy_engine/scanpy_engine.py @@ -35,6 +35,10 @@ class ScanpyEngine(CXGDriver): self.diffexp_options = ["ttest"] self._create_schema() + # TODO: temporary work-arounds + self._IEEE754_X_warning_issued = False + self._IEEE754_special_values_workaround_annotations() + def _alias_annotation_names(self, axis, name): """ Do all user-specified annotation aliasing. @@ -172,6 +176,52 @@ class ScanpyEngine(CXGDriver): f"`cellxgene prepare --layout {self.layout_method} ` " f"to solve this problem. ") + def _IEEE754_special_values_workaround_annotations(self): + """ + TODO: temporary workaround + + Because all floating point data is serialized to JSON, and JSON has no means of representing + non-finite, floating point special values (NaN, +/-Infinity, etc), we include this temporary + work-around. + + This will likely be removed in the future, contingent upon improved marshalling. + + Where non-finite floating point is present in obs, var or X: + * issue a warning to the user that these values will be treated as zeros. + * set the value to zero within the in-memory data (self.data) + """ + for ax in Axis: + curr_axis = getattr(self.data, str(ax)) + for ann in curr_axis: + dtype = curr_axis[ann].dtype + if dtype.kind == 'f': + not_finite = np.isfinite(curr_axis[ann]) == False # noqa: E712 + if np.count_nonzero(not_finite) > 0: + warnings.warn( + f"{str(ax).title()} annotation '{ann}' contains floating point NaN or Infinities. " + f"These values will be treated as zero." + ) + curr_axis[ann][not_finite] = 0 + + def _IEEE754_special_values_workaround_X(self, _X): + """ + TODO: temporary workaround + + See comments in _IEEE754_special_values_workaround_annotations + """ + not_finite = np.isfinite(_X) == False # noqa: E712 + if np.count_nonzero(not_finite) > 0: + _X[not_finite] = 0 + if not self._IEEE754_X_warning_issued: + # only want to issue this warning once. + warnings.warn( + "Dataframe X contains floating point NaN or Infinities. " + "These values will be treated as zero." + ) + self._IEEE754_X_warning_issued = True + + return _X + def filter_dataframe(self, filter): """ Filter cells from data and return a subset of the data. They can operate on both obs and var dimension with @@ -323,6 +373,7 @@ class ScanpyEngine(CXGDriver): _X = _X.toarray() var_index_sliced = self.data.var.index[var_selector] obs_index_sliced = self.data.obs.index[obs_selector] + _X = self._IEEE754_special_values_workaround_X(_X) if axis == Axis.OBS: result = { "var": var_index_sliced.tolist(),