Remove heatmap, add diffexp info to histograms (#339)

* Create Release_Validation_Recipe.md

* compose middle ware for redux devtools

* update package.json and lock

* remove heatmap, add to left side bar

* redux devtools extension
This commit is contained in:
Colin Megill
2018-10-16 16:29:20 -07:00
committed by GitHub
parent 76ec29734a
commit 952578680a
11 changed files with 266 additions and 100 deletions
+34 -29
View File
@@ -2054,7 +2054,7 @@
}, },
"babel-plugin-syntax-object-rest-spread": { "babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0", "version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
"dev": true "dev": true
}, },
@@ -2489,7 +2489,7 @@
}, },
"browserify-aes": { "browserify-aes": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -2526,7 +2526,7 @@
}, },
"browserify-rsa": { "browserify-rsa": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -2580,7 +2580,7 @@
}, },
"buffer": { "buffer": {
"version": "4.9.1", "version": "4.9.1",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -3258,7 +3258,7 @@
}, },
"create-hash": { "create-hash": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -3271,7 +3271,7 @@
}, },
"create-hmac": { "create-hmac": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -3945,7 +3945,7 @@
}, },
"diffie-hellman": { "diffie-hellman": {
"version": "5.0.3", "version": "5.0.3",
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -4522,7 +4522,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -4699,7 +4699,7 @@
}, },
"events": { "events": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
}, },
"evp_bytestokey": { "evp_bytestokey": {
@@ -4993,7 +4993,7 @@
}, },
"finalhandler": { "finalhandler": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -5717,7 +5717,7 @@
}, },
"get-stream": { "get-stream": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
"dev": true "dev": true
}, },
@@ -6096,7 +6096,7 @@
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "http://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
"integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -6172,7 +6172,7 @@
}, },
"http-errors": { "http-errors": {
"version": "1.6.3", "version": "1.6.3",
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -6395,7 +6395,7 @@
}, },
"is-builtin-module": { "is-builtin-module": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -7394,7 +7394,7 @@
}, },
"json5": { "json5": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true "dev": true
}, },
@@ -7484,7 +7484,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -7813,7 +7813,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }
@@ -7938,7 +7938,7 @@
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true "dev": true
}, },
@@ -7983,7 +7983,7 @@
}, },
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -9695,7 +9695,7 @@
}, },
"parse-asn1": { "parse-asn1": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -10291,7 +10291,7 @@
}, },
"react-redux": { "react-redux": {
"version": "5.0.7", "version": "5.0.7",
"resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
"integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==",
"requires": { "requires": {
"hoist-non-react-statics": "^2.5.0", "hoist-non-react-statics": "^2.5.0",
@@ -10355,7 +10355,7 @@
}, },
"readable-stream": { "readable-stream": {
"version": "2.3.6", "version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -10698,6 +10698,11 @@
"symbol-observable": "^1.2.0" "symbol-observable": "^1.2.0"
} }
}, },
"redux-devtools-extension": {
"version": "2.13.5",
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.5.tgz",
"integrity": "sha512-QQ9BRy77oURHMdGys9rfQcCQDzXZ1T4oW+eUyE5Cg7DNVau69HJzc4YNDMOmpi0Dzpi1zOQgQ2rUpgJta4Lfqg=="
},
"redux-thunk": { "redux-thunk": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
@@ -11368,7 +11373,7 @@
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
}, },
@@ -11555,7 +11560,7 @@
}, },
"sha.js": { "sha.js": {
"version": "2.4.11", "version": "2.4.11",
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -12009,7 +12014,7 @@
}, },
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -12245,7 +12250,7 @@
}, },
"through": { "through": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true "dev": true
}, },
@@ -12884,7 +12889,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }
@@ -13542,7 +13547,7 @@
}, },
"wrap-ansi": { "wrap-ansi": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -13650,7 +13655,7 @@
}, },
"yargs": { "yargs": {
"version": "11.1.0", "version": "11.1.0",
"resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
"integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
"dev": true, "dev": true,
"requires": { "requires": {
+1
View File
@@ -47,6 +47,7 @@
"react-icons": "^3.2.0", "react-icons": "^3.2.0",
"react-redux": "^5.0.6", "react-redux": "^5.0.6",
"redux": "^4.0.1", "redux": "^4.0.1",
"redux-devtools-extension": "^2.13.5",
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"regl": "^1.3.1", "regl": "^1.3.1",
"scroll-speed": "^1.0.0", "scroll-speed": "^1.0.0",
@@ -16,7 +16,10 @@ import actions from "../../actions";
@connect(state => ({ @connect(state => ({
world: state.controls.world, world: state.controls.world,
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
crossfilter: state.controls.crossfilter, crossfilter: state.controls.crossfilter,
differential: state.differential,
initializeRanges: _.get(state.controls.world, "summary.obs"), initializeRanges: _.get(state.controls.world, "summary.obs"),
colorAccessor: state.controls.colorAccessor, colorAccessor: state.controls.colorAccessor,
colorScale: state.controls.colorScale, colorScale: state.controls.colorScale,
@@ -208,8 +211,38 @@ class HistogramBrush extends React.Component {
} }
} }
handleSetGeneAsScatterplotX() {
return () => {
const { dispatch, field } = this.props;
dispatch({
type: "set scatterplot x",
data: field
});
};
}
handleSetGeneAsScatterplotY() {
return () => {
const { dispatch, field } = this.props;
dispatch({
type: "set scatterplot y",
data: field
});
};
}
render() { render() {
const { field, ranges, colorAccessor, isUserDefined } = this.props; const {
field,
colorAccessor,
isUserDefined,
isDiffExp,
diffExp_avgDiff,
diffExp_set1AvgExp,
diffExp_set2AvgExp,
scatterplotXXaccessor,
scatterplotYYaccessor
} = this.props;
return ( return (
<div <div
@@ -234,6 +267,84 @@ class HistogramBrush extends React.Component {
remove remove
</span> </span>
) : null} ) : null}
{isDiffExp ? (
<span>
<span
style={{
fontSize: globals.tiniestFontSize,
marginLeft: 7
}}
>
<strong>1:</strong>
{` ${diffExp_set1AvgExp.toPrecision(2)}`}
</span>
<span
style={{
fontSize: globals.tiniestFontSize,
marginLeft: 7,
backgroundColor: globals.lighterGrey,
padding: 2
}}
>
<strong>2:</strong>
{` ${diffExp_set2AvgExp.toPrecision(2)}`}
</span>
<span
style={{
fontSize: globals.tiniestFontSize,
marginLeft: 7
}}
>
{`Av. Diff: ${diffExp_avgDiff.toFixed(2)}`}
</span>
<span
onClick={this.handleSetGeneAsScatterplotX(field).bind(this)}
style={{
fontSize: 16,
color:
scatterplotXXaccessor === field
? "white"
: globals.brightBlue,
cursor: "pointer",
position: "relative",
top: 1,
fontWeight: 700,
marginRight: 4,
borderRadius: 3,
padding: "2px 3px",
backgroundColor:
scatterplotXXaccessor === field
? globals.brightBlue
: "inherit"
}}
>
X
</span>
<span
onClick={this.handleSetGeneAsScatterplotY(field).bind(this)}
style={{
fontSize: 16,
color:
scatterplotYYaccessor === field
? "white"
: globals.brightBlue,
cursor: "pointer",
position: "relative",
top: 1,
fontWeight: 700,
marginRight: 4,
borderRadius: 3,
padding: "2px 3px",
backgroundColor:
scatterplotYYaccessor === field
? globals.brightBlue
: "inherit"
}}
>
Y
</span>
</span>
) : null}
</div> </div>
<svg <svg
width={this.width} width={this.width}
@@ -3,9 +3,7 @@ import React from "react";
import _ from "lodash"; import _ from "lodash";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { FaChevronRight } from "react-icons/fa"; import { FaChevronRight, FaChevronDown, FaPaintBrush } from "react-icons/fa";
import { FaChevronDown } from "react-icons/fa";
import { FaPaintBrush } from "react-icons/fa";
import * as globals from "../../globals"; import * as globals from "../../globals";
import Value from "./value"; import Value from "./value";
@@ -126,7 +124,7 @@ class Category extends React.Component {
cursor: "pointer", cursor: "pointer",
display: "inline-block", display: "inline-block",
position: "relative", position: "relative",
top: -1 top: 2
}} }}
onClick={() => { onClick={() => {
this.setState({ isExpanded: !isExpanded }); this.setState({ isExpanded: !isExpanded });
@@ -155,7 +153,7 @@ class Category extends React.Component {
// backgroundColor: this.props.colorAccessor === this.props.metadataField ? globals.brightBlue : "inherit", // backgroundColor: this.props.colorAccessor === this.props.metadataField ? globals.brightBlue : "inherit",
display: "inline-block", display: "inline-block",
position: "relative", position: "relative",
top: -1, top: 2,
cursor: "pointer" cursor: "pointer"
}} }}
> >
@@ -196,6 +194,7 @@ class Categories extends React.Component {
// overflow: "auto", // overflow: "auto",
}} }}
> >
<p> Categorical Metadata </p>
{_.map(ranges, (value, key) => { {_.map(ranges, (value, key) => {
const isColorField = key.includes("color") || key.includes("Color"); const isColorField = key.includes("color") || key.includes("Color");
if (value.options && !isColorField && key !== "name") { if (value.options && !isColorField && key !== "name") {
@@ -37,8 +37,6 @@ class Continuous extends React.Component {
}; };
} }
componentDidUpdate() {}
render() { render() {
const { ranges, obsAnnotations, schema } = this.props; const { ranges, obsAnnotations, schema } = this.props;
if (schema && !this.continuousChecked) { if (schema && !this.continuousChecked) {
@@ -3,7 +3,7 @@ import React from "react";
import _ from "lodash"; import _ from "lodash";
import memoize from "memoize-one"; import memoize from "memoize-one";
import { connect } from "react-redux"; import { connect } from "react-redux";
import ReactAutocomplete from "react-autocomplete"; /* http://emilebres.github.io/react-virtualized-checkbox/ */ // import ReactAutocomplete from "react-autocomplete"; /* http://emilebres.github.io/react-virtualized-checkbox/ */
import getContrast from "font-color-contrast"; // https://www.npmjs.com/package/font-color-contrast import getContrast from "font-color-contrast"; // https://www.npmjs.com/package/font-color-contrast
import { FaPaintBrush } from "react-icons/fa"; import { FaPaintBrush } from "react-icons/fa";
import * as d3 from "d3"; import * as d3 from "d3";
@@ -93,6 +93,8 @@ class GeneExpression extends React.Component {
style={{ style={{
display: "inline-block", display: "inline-block",
marginLeft: 7, marginLeft: 7,
position: "relative",
top: 5,
color: globals.brightBlue, color: globals.brightBlue,
fontSize: 22 fontSize: 22
}} }}
@@ -135,6 +137,9 @@ class GeneExpression extends React.Component {
field={name} field={name}
ranges={d3.extent(values)} ranges={d3.extent(values)}
isDiffExp isDiffExp
diffExp_avgDiff={value[1]}
diffExp_set1AvgExp={value[4]}
diffExp_set2AvgExp={value[5]}
/> />
); );
} }
+6 -2
View File
@@ -393,7 +393,9 @@ class Graph extends React.Component {
border: border:
mode === "brush" ? "1px solid black" : "1px solid white", mode === "brush" ? "1px solid black" : "1px solid white",
backgroundColor: "white", backgroundColor: "white",
padding: 5, padding: "5px 5px 2px 5px",
position: "relative",
top: 2,
marginRight: 10, marginRight: 10,
borderRadius: 3 borderRadius: 3
}} }}
@@ -413,7 +415,9 @@ class Graph extends React.Component {
border: border:
mode === "zoom" ? "1px solid black" : "1px solid white", mode === "zoom" ? "1px solid black" : "1px solid white",
backgroundColor: "white", backgroundColor: "white",
padding: 5, padding: "5px 5px 2px 5px",
position: "relative",
top: 2,
marginRight: 10, marginRight: 10,
borderRadius: 3 borderRadius: 3
}} }}
+24 -58
View File
@@ -12,7 +12,9 @@ import DynamicScatterplot from "./scatterplot/scatterplot";
@connect(state => ({ @connect(state => ({
responsive: state.responsive, responsive: state.responsive,
datasetTitle: _.get(state.config, "displayNames.dataset") datasetTitle: _.get(state.config, "displayNames.dataset"),
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
scatterplotYYaccessor: state.controls.scatterplotYYaccessor
})) }))
class LeftSideBar extends React.Component { class LeftSideBar extends React.Component {
constructor(props) { constructor(props) {
@@ -24,86 +26,48 @@ class LeftSideBar extends React.Component {
render() { render() {
const { currentTab } = this.state; const { currentTab } = this.state;
const { responsive, datasetTitle } = this.props; const {
responsive,
datasetTitle,
scatterplotXXaccessor,
scatterplotYYaccessor
} = this.props;
/* /*
this magic number should be made less fragile, this magic number should be made less fragile,
if cellxgene logo or tabs change, this must as well if cellxgene logo or tabs change, this must as well
*/ */
const metadataSectionPadding = currentTab === "metadata" ? 88 : 450; const metadataSectionPadding =
scatterplotXXaccessor && scatterplotYYaccessor ? 450 : 0;
return ( return (
<div style={{ position: "fixed" }}> <div style={{ position: "fixed" }}>
<p <p
style={{ style={{
margin: 10, position: "fixed",
left: responsive.width / 2,
top: 14,
margin: 0,
fontSize: 24, fontSize: 24,
color: globals.lightGrey, color: globals.darkerGrey,
fontWeight: 700, fontWeight: 700,
width: "100%" width: "100%"
}} }}
> >
cellxgene &nbsp; cellxgene: &nbsp;
{datasetTitle} {datasetTitle}
</p> </p>
<div style={{ padding: 10 }}>
<button
type="button"
style={{
padding: "none",
outline: 0,
fontSize: 14,
fontWeight: currentTab === "metadata" ? 700 : 400,
fontStyle: currentTab === "metadata" ? "inherit" : "italic",
cursor: "pointer",
border: "none",
backgroundColor: "#FFF",
borderTop: "none",
borderBottom: "none",
borderRight: "none",
borderLeft: "none"
}}
onClick={() => {
this.setState({ currentTab: "metadata" });
}}
>
Metadata
</button>
<button
type="button"
style={{
padding: "none",
outline: 0,
fontSize: 14,
fontWeight: currentTab === "expression" ? 700 : 400,
fontStyle: currentTab === "expression" ? "inherit" : "italic",
cursor: "pointer",
border: "none",
backgroundColor: "#FFF",
borderTop: "none",
borderBottom: "none",
borderRight: "none",
borderLeft: "none"
}}
onClick={() => {
this.setState({ currentTab: "expression" });
}}
>
Expression
</button>
</div>
<div <div
style={{ style={{
height: responsive.height - metadataSectionPadding, height: responsive.height - metadataSectionPadding,
width: 400, width: 400,
padding: 10, padding: "0px 10px 10px 10px",
overflowY: "auto", overflowY: "auto",
overflowX: "hidden" overflowX: "hidden"
}} }}
> >
{currentTab === "metadata" ? <Categorical /> : null} <Categorical />
{currentTab === "metadata" ? <GeneExpression /> : null} <GeneExpression />
{currentTab === "metadata" ? <Continuous /> : null} <Continuous />
{currentTab === "expression" ? <Heatmap /> : null}
</div> </div>
<div <div
style={{ style={{
@@ -112,7 +76,9 @@ class LeftSideBar extends React.Component {
left: 0 left: 0
}} }}
> >
{currentTab === "expression" ? <DynamicScatterplot /> : null} {scatterplotXXaccessor && scatterplotYYaccessor ? (
<DynamicScatterplot />
) : null}
</div> </div>
<div style={{ position: "fixed", bottom: 0, right: 0 }}> <div style={{ position: "fixed", bottom: 0, right: 0 }}>
{currentTab === "metadata" ? <ExpressionButtons /> : null} {currentTab === "metadata" ? <ExpressionButtons /> : null}
+4 -2
View File
@@ -3,6 +3,7 @@ import { combineReducers, createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk"; import thunk from "redux-thunk";
import updateURLMiddleware from "../middleware/updateURLMiddleware"; import updateURLMiddleware from "../middleware/updateURLMiddleware";
import updateCellColors from "../middleware/updateCellColors"; import updateCellColors from "../middleware/updateCellColors";
import { composeWithDevTools } from "redux-devtools-extension";
import config from "./config"; import config from "./config";
import differential from "./differential"; import differential from "./differential";
@@ -18,8 +19,9 @@ const Reducer = combineReducers({
const store = createStore( const store = createStore(
Reducer, Reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), composeWithDevTools(
applyMiddleware(thunk, updateURLMiddleware, updateCellColors) applyMiddleware(thunk, updateURLMiddleware, updateCellColors)
)
); );
export default store; export default store;
+75
View File
@@ -0,0 +1,75 @@
# Pre-release Validation Plan
_This document contains a general purpose test plan for validating cellxgene prior to release_.
All steps are expected to pass with no errors or malfunctions. Tester should check:
* CLI for errors (eg, build error, engine error)
* Browser console for errors
* Expected CLI and/or browser UI function
## [Backend Test](#backend-test)
### Getting started build & install validation:
Goal: validate build, install and example demo correctness, per Getting Started instructions.
1. Clean clone of the cellxgene repo into a local directory
2. Follow build & install instructions from the Getting Started guide
* Confirm no build or install errors
* Confirm `cellxgene --help` functions correctly
3. Follow the example data set demo startup from Getting Started guide and confirm front-end data loads correctly
4. Confirm all package (and other) version dependencies are correct and match
### Tabula Muris
Goal: basic functional validation of b/e functions using Tabula Muris data and the scanpy engine.
1. Precondition: cellxgene built & installed.
2. Load the Tabula Muris data set: `cellxgene --title 'T. Muris' scanpy directory-name/`
3. Verify all metadata selectors display and have correct type/options:
* *TODO:* _need list of metadata and their type_
* ...
4. Verify default graph display has expected layout. _need screen shot of expected layout_
5. Verify selection controls work as expected:
* continuous metadata field
* categorical metadata field
* graph/lasso select
6. Verify color by metadata type
7. Select two cell sets and confirm differential expression compute succeeds
6. Verify expression scatter plot is correct
## [Front-end Compatibility Test](#frontend-compatability-test)
Goal: verify front-end UI compatibility with a given browser variant/version/platform.
1. Start back-end on PBM3K data set
2. Load UI
3. Verify all major UI modes/functions:
* Graph display
* Metadata selector display
* Title display
* Selection - single and multiple fields - correctly display in cluster graph
* Regraph & reset function correctly
* Differential expression calc & scatter plot display
* All graphs maintain consistent selection state
* All selection widgets (eg, continuous metadata selector) maintain correct status (consistent with graph displays)
4. Verify overall performance is reasonable/interactive
5. Verify no errors on CLI or browser console
## [End-to-end Functional Test](#e2e-functional-test)
Goal: confirm end-to-end functional behavior is as expected.
### ScanPy engine
1. Basic data load and display
* ...
2. Select & multi-select of metadata and coordinates
* ...
3. Color by metadata
* ...
4. Regraph / reset
* ...
5. Differential expression: scatterplot, top-N genes, etc.
* ...
6. Color by expression
* ...
7. Arbitrary gene expression
* ...