From df671192be84e675e5d10928cdca453e5038dc90 Mon Sep 17 00:00:00 2001 From: Colin Megill Date: Mon, 22 Oct 2018 15:46:37 -0400 Subject: [PATCH] Begin integrating blueprint (#359) * toast test * modify webpack build to allow for global CSS; use CSS modules to scope component styling * remove heatmap * add label to index resets * swapping out buttons for blueprint * adding constants to globals * swapping out blueprint buttons * title position, sidebar improvements * sidebar styles * adding toasts for validation errors * zebra section trial * integrating blueprint, switching buttons over, breaking out scatter * clean up console --- .../webpack/webpack.config.dev.js | 21 +- .../webpack/webpack.config.prod.js | 38 ++- client/index.html | 4 +- client/index_template.html | 15 +- client/package-lock.json | 271 +++++++++++++++--- client/package.json | 4 + .../components/brushableHistogram/index.js | 12 +- .../src/components/categorical/categorical.js | 14 +- client/src/components/categorical/category.js | 83 +++--- client/src/components/categorical/value.js | 57 ++-- .../src/components/continuous/continuous.js | 17 +- .../continuous/parallelCoordinates.css | 40 +-- .../src/components/continuousLegend/index.js | 16 +- .../components/expression/cellSetButtons.js | 71 ----- .../components/expression/diffExpHeatmap.js | 83 ------ .../src/components/expression/expression.css | 0 .../src/components/expression/heatmapRow.js | 154 ---------- .../components/expression/heatmapSquare.js | 30 -- client/src/components/framework/buttons.css | 2 +- client/src/components/framework/container.css | 2 +- client/src/components/framework/toasters.js | 12 + .../geneExpression/cellSetButtons.js | 46 +++ .../expressionButtons.js | 53 +--- client/src/components/geneExpression/index.js | 167 ++++++----- client/src/components/graph/graph.css | 8 +- client/src/components/graph/graph.js | 81 ++---- client/src/components/leftsidebar.js | 47 ++- .../components/scatterplot/scatterplot.css | 9 +- .../src/components/scatterplot/scatterplot.js | 41 ++- client/src/components/scatterplot/util.js | 2 +- client/src/globals.js | 37 ++- client/src/index.css | 9 + client/src/index.js | 2 + client/src/reducers/controls.js | 6 + 34 files changed, 717 insertions(+), 737 deletions(-) delete mode 100644 client/src/components/expression/cellSetButtons.js delete mode 100644 client/src/components/expression/diffExpHeatmap.js delete mode 100644 client/src/components/expression/expression.css delete mode 100644 client/src/components/expression/heatmapRow.js delete mode 100644 client/src/components/expression/heatmapSquare.js create mode 100644 client/src/components/framework/toasters.js create mode 100644 client/src/components/geneExpression/cellSetButtons.js rename client/src/components/{expression => geneExpression}/expressionButtons.js (58%) diff --git a/client/configuration/webpack/webpack.config.dev.js b/client/configuration/webpack/webpack.config.dev.js index 76f9ae6a..3b273a11 100644 --- a/client/configuration/webpack/webpack.config.dev.js +++ b/client/configuration/webpack/webpack.config.dev.js @@ -6,6 +6,8 @@ const HtmlWebpackPlugin = require("html-webpack-plugin"); const src = path.resolve("src"); const nodeModules = path.resolve("node_modules"); +const babelOptions = require("../babel/babel.dev"); + module.exports = { mode: "development", devtool: "eval", @@ -22,11 +24,12 @@ module.exports = { test: /\.js$/, include: src, loader: "babel-loader", - options: require("../babel/babel.dev") + options: babelOptions }, { test: /\.css$/, - include: [src, nodeModules], + include: src, + exclude: [path.resolve(src, "index.css")], loader: [ { loader: "style-loader" @@ -35,12 +38,24 @@ module.exports = { loader: "css-loader", options: { modules: true, - importLoaders: 1, localIdentName: "[name]__[local]___[hash:base64:5]" } } ] }, + { + test: /index\.css$/, + include: [path.resolve(src, "index.css")], + loader: [ + { + loader: "style-loader" + }, + { + loader: "css-loader" + } + ] + }, + { test: /\.json$/, include: [src, nodeModules], loader: "json-loader" }, { test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, diff --git a/client/configuration/webpack/webpack.config.prod.js b/client/configuration/webpack/webpack.config.prod.js index bd60898b..6cffc8b4 100644 --- a/client/configuration/webpack/webpack.config.prod.js +++ b/client/configuration/webpack/webpack.config.prod.js @@ -1,6 +1,5 @@ // jshint esversion: 6 const path = require("path"); -const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const SWPrecacheWebpackPlugin = require("sw-precache-webpack-plugin"); @@ -9,6 +8,8 @@ const HtmlWebpackInlineSourcePlugin = require("html-webpack-inline-source-plugin const src = path.resolve("src"); const nodeModules = path.resolve("node_modules"); +const babelOptions = require("../babel/babel.prod"); + const publicPath = "/"; module.exports = { @@ -16,7 +17,7 @@ module.exports = { bail: true, cache: false, devtool: "cheap-source-map", - entry: ["./src/index"], + entry: ["./src/index.js"], output: { path: path.resolve("build"), filename: "static/js/[name].[chunkhash:8].js", @@ -28,15 +29,14 @@ module.exports = { test: /\.js$/, include: src, loader: "babel-loader", - options: require("../babel/babel.prod") + options: babelOptions }, { test: /\.css$/, - include: [src, nodeModules], - loader: [ - { - loader: MiniCssExtractPlugin.loader - }, + include: src, + exclude: [path.resolve(src, "index.css")], + use: [ + MiniCssExtractPlugin.loader, { loader: "css-loader", options: { @@ -47,6 +47,19 @@ module.exports = { } ] }, + { + test: /index\.css$/, + include: [path.resolve(src, "index.css")], + use: [ + MiniCssExtractPlugin.loader, + { + loader: "css-loader", + options: { + importLoaders: 1 + } + } + ] + }, { test: /\.json$/, include: [src, nodeModules], @@ -57,7 +70,10 @@ module.exports = { test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, include: [src, nodeModules], loader: "file-loader", - query: { name: "static/media/[name].[hash:8].[ext]" } + options: { + name: "[name].[hash:8].[ext]", + outputPath: "static/media/" + } }, { test: /\.(mp4|webm)(\?.*)?$/, @@ -97,7 +113,7 @@ module.exports = { }) ], performance: { - maxEntrypointSize: 750000, - maxAssetSize: 750000 + maxEntrypointSize: 2000000, + maxAssetSize: 2000000 } }; diff --git a/client/index.html b/client/index.html index b0eefdd0..08259783 100644 --- a/client/index.html +++ b/client/index.html @@ -6,9 +6,9 @@ cellxgene diff --git a/client/package-lock.json b/client/package-lock.json index 6f9ce9e3..583d159d 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -913,6 +913,47 @@ "to-fast-properties": "^2.0.0" } }, + "@blueprintjs/core": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@blueprintjs/core/-/core-3.7.0.tgz", + "integrity": "sha512-fr1jgAY/sPWJ7BorebuyLQKTTk7x+/1suayaxKVh1WMQ7aIi3Zb7HnJPEVFQyaT+9rVl97b7/2DiID3N8/UGMw==", + "requires": { + "@blueprintjs/icons": "^3.2.0", + "@types/dom4": "^2.0.0", + "classnames": "^2.2", + "dom4": "^2.0.1", + "normalize.css": "^8.0.0", + "popper.js": "^1.14.1", + "react-popper": "^1.0.0", + "react-transition-group": "^2.2.1", + "resize-observer-polyfill": "^1.5.0", + "tslib": "^1.9.0" + } + }, + "@blueprintjs/icons": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@blueprintjs/icons/-/icons-3.2.0.tgz", + "integrity": "sha512-MoI4TdZ2QMM9DEd+/vJOMSlhuvPID3Zip0TB/MB1J7p7GnUThIRq2FlETMUg6ig1GZweAWNl7cUtYFNHZ3EiUQ==", + "requires": { + "classnames": "^2.2", + "tslib": "^1.9.0" + } + }, + "@blueprintjs/select": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@blueprintjs/select/-/select-3.2.0.tgz", + "integrity": "sha512-kieg23ktzCXBUT7oVKBwlnPrjpwH8GgB722BL4nMV+c9cnt9gHuhk6eGORd3w8tK9gI85F/+brVkimbmQShVZg==", + "requires": { + "@blueprintjs/core": "^3.6.0", + "classnames": "^2.2", + "tslib": "^1.9.0" + } + }, + "@types/dom4": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/dom4/-/dom4-2.0.1.tgz", + "integrity": "sha512-kSkVAvWmMZiCYtvqjqQEwOmvKwcH+V4uiv3qPQ8pAh1Xl39xggGEo8gHUqV4waYGHezdFw0rKBR8Jt0CrQSDZA==" + }, "@webassemblyjs/ast": { "version": "1.7.8", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.8.tgz", @@ -1632,6 +1673,11 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -2054,7 +2100,7 @@ }, "babel-plugin-syntax-object-rest-spread": { "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=", "dev": true }, @@ -2167,7 +2213,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" @@ -2176,8 +2221,7 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" } } }, @@ -2489,7 +2533,7 @@ }, "browserify-aes": { "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==", "dev": true, "requires": { @@ -2526,7 +2570,7 @@ }, "browserify-rsa": { "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=", "dev": true, "requires": { @@ -2580,7 +2624,7 @@ }, "buffer": { "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=", "dev": true, "requires": { @@ -2951,6 +2995,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", @@ -3228,8 +3277,7 @@ "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", - "dev": true + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" }, "core-util-is": { "version": "1.0.2", @@ -3258,7 +3306,7 @@ }, "create-hash": { "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==", "dev": true, "requires": { @@ -3271,7 +3319,7 @@ }, "create-hmac": { "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==", "dev": true, "requires": { @@ -3283,6 +3331,15 @@ "sha.js": "^2.4.8" } }, + "create-react-context": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.3.tgz", + "integrity": "sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==", + "requires": { + "fbjs": "^0.8.0", + "gud": "^1.0.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -3945,7 +4002,7 @@ }, "diffie-hellman": { "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==", "dev": true, "requires": { @@ -3993,6 +4050,11 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.3.1.tgz", + "integrity": "sha512-2Sm+JaYn74OiTM2wHvxJOo3roiq/h25Yi69Fqk269cNUwIXsCvATB6CRSFC9Am/20G2b28hGv/+7NiWydIrPvg==" + }, "dom-scroll-into-view": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-1.0.1.tgz", @@ -4025,6 +4087,11 @@ "urijs": "^1.16.1" } }, + "dom4": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/dom4/-/dom4-2.1.3.tgz", + "integrity": "sha512-begvh4z5GV0kyxx+YgJZ7sIo/jsELx/v7MQxoLZpOvT5yFo18X8dfgtUmKAwdGuyMeugncylarLHlO4gIK6YNw==" + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -4152,6 +4219,14 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -4539,7 +4614,7 @@ }, "load-json-file": { "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=", "dev": true, "requires": { @@ -4716,7 +4791,7 @@ }, "events": { "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=" }, "evp_bytestokey": { @@ -4950,6 +5025,27 @@ "bser": "^2.0.0" } }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + } + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -5010,7 +5106,7 @@ }, "finalhandler": { "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==", "dev": true, "requires": { @@ -5734,7 +5830,7 @@ }, "get-stream": { "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=", "dev": true }, @@ -5862,6 +5958,11 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "handlebars": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", @@ -6113,7 +6214,7 @@ }, "html-webpack-plugin": { "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=", "dev": true, "requires": { @@ -6189,7 +6290,7 @@ }, "http-errors": { "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=", "dev": true, "requires": { @@ -6412,7 +6513,7 @@ }, "is-builtin-module": { "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=", "dev": true, "requires": { @@ -6645,8 +6746,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-symbol": { "version": "1.0.2", @@ -6696,6 +6796,15 @@ "isarray": "1.0.0" } }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -7411,7 +7520,7 @@ }, "json5": { "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=", "dev": true }, @@ -7501,7 +7610,7 @@ }, "load-json-file": { "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=", "dev": true, "requires": { @@ -7830,7 +7939,7 @@ "dependencies": { "minimist": { "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=", "dev": true } @@ -7955,7 +8064,7 @@ }, "minimist": { "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=", "dev": true }, @@ -8000,7 +8109,7 @@ }, "mkdirp": { "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=", "dev": true, "requires": { @@ -8128,6 +8237,15 @@ "lower-case": "^1.1.1" } }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8221,6 +8339,11 @@ "remove-trailing-separator": "^1.0.1" } }, + "normalize.css": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.0.tgz", + "integrity": "sha512-iXcbM3NWr0XkNyfiSBsoPezi+0V92P9nj84yVV1/UZxRUrGczgX/X91KMAGM0omWLY2+2Q1gKD/XRn4gQRDB2A==" + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -9712,7 +9835,7 @@ }, "parse-asn1": { "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==", "dev": true, "requires": { @@ -9899,6 +10022,11 @@ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, + "popper.js": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz", + "integrity": "sha1-juwdj/AqWjoVLdQ0FKFce3n9abY=" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -10045,6 +10173,14 @@ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "dev": true }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -10306,9 +10442,27 @@ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.2.0.tgz", "integrity": "sha512-ZWqIiOr5wTqtE6NNM9JgWBgNbq2JRi79rmqf2j50V1ewC6LiwKFhq7J/AjaVKBi5oPE4/9JN/jMKaVrJlIQoiw==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-popper": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.0.2.tgz", + "integrity": "sha512-vjZ94ki8sfCAg45MMi4uqnUUWdzbnYkb95sR2+HgiMaAPzQcy4DfDKYtYUOhhE+sdtkufWcUHLv09DmH2Js57w==", + "requires": { + "babel-runtime": "6.x.x", + "create-react-context": "^0.2.1", + "popper.js": "^1.14.1", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.5", + "warning": "^3.0.0" + } + }, "react-redux": { "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==", "requires": { "hoist-non-react-statics": "^2.5.0", @@ -10328,6 +10482,17 @@ "shallowequal": "^1.0.1" } }, + "react-transition-group": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.0.tgz", + "integrity": "sha512-qYB3JBF+9Y4sE4/Mg/9O6WFpdoYjeeYqx0AFb64PTazVy8RPMiE3A47CG9QmM4WJ/mzDiZYslV+Uly6O1Erlgw==", + "requires": { + "dom-helpers": "^3.3.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -10372,7 +10537,7 @@ }, "readable-stream": { "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==", "dev": true, "requires": { @@ -10957,6 +11122,11 @@ "resolve-from": "^1.0.0" } }, + "resize-observer-polyfill": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.0.tgz", + "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", @@ -11390,7 +11560,7 @@ }, "minimist": { "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=", "dev": true }, @@ -11566,8 +11736,7 @@ "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "setprototypeof": { "version": "1.1.0", @@ -11577,7 +11746,7 @@ }, "sha.js": { "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==", "dev": true, "requires": { @@ -12031,7 +12200,7 @@ }, "strip-ansi": { "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=", "dev": true, "requires": { @@ -12267,7 +12436,7 @@ }, "through": { "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=", "dev": true }, @@ -12413,8 +12582,7 @@ "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", - "dev": true + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, "tty-browserify": { "version": "0.0.0", @@ -12456,12 +12624,22 @@ "mime-types": "~2.1.18" } }, + "typed-styles": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.5.tgz", + "integrity": "sha512-ht+rEe5UsdEBAa3gr64+QjUOqjOLJfWLvl5HZR5Ev9uo/OnD3p43wPeFSB1hNFc13GXQF/JU1Bn0YHLUqBRIlw==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "ua-parser-js": { + "version": "0.7.18", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz", + "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==" + }, "uglify-js": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", @@ -12894,6 +13072,14 @@ "makeerror": "1.0.x" } }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "^1.0.0" + } + }, "watch": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", @@ -12906,7 +13092,7 @@ "dependencies": { "minimist": { "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=", "dev": true } @@ -13501,6 +13687,11 @@ "iconv-lite": "0.4.24" } }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + }, "whatwg-mimetype": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz", @@ -13564,7 +13755,7 @@ }, "wrap-ansi": { "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=", "dev": true, "requires": { @@ -13672,7 +13863,7 @@ }, "yargs": { "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==", "dev": true, "requires": { diff --git a/client/package.json b/client/package.json index 2a2e363c..456fc5c9 100644 --- a/client/package.json +++ b/client/package.json @@ -27,6 +27,9 @@ "eslint-scope": "3.7.1" }, "dependencies": { + "@blueprintjs/core": "^3.7.0", + "@blueprintjs/icons": "^3.2.0", + "@blueprintjs/select": "^3.2.0", "canvas-fit": "^1.5.0", "d3": "^4.10.0", "d3-scale-chromatic": "^1.3.0", @@ -38,6 +41,7 @@ "memoize-one": "^4.0.0", "mouse-position": "^2.0.1", "mouse-pressed": "^1.0.0", + "normalize.css": "^8.0.0", "orbit-camera": "^1.0.0", "query-string": "^6.1.0", "react": "^16.4.2", diff --git a/client/src/components/brushableHistogram/index.js b/client/src/components/brushableHistogram/index.js index 8dc06062..d9401bdc 100644 --- a/client/src/components/brushableHistogram/index.js +++ b/client/src/components/brushableHistogram/index.js @@ -230,9 +230,9 @@ class HistogramBrush extends React.Component { colorAccessor, isUserDefined, isDiffExp, - diffExp_avgDiff, - diffExp_set1AvgExp, - diffExp_set2AvgExp, + avgDiff, + set1AvgExp, + set2AvgExp, scatterplotXXaccessor, scatterplotYYaccessor } = this.props; @@ -269,7 +269,7 @@ class HistogramBrush extends React.Component { }} > 1: - {` ${diffExp_set1AvgExp.toPrecision(2)}`} + {` ${set1AvgExp.toPrecision(2)}`} 2: - {` ${diffExp_set2AvgExp.toPrecision(2)}`} + {` ${set2AvgExp.toPrecision(2)}`} - {`Av. Diff: ${diffExp_avgDiff.toFixed(2)}`} + {`Av. Diff: ${avgDiff.toFixed(2)}`} -

Categorical Metadata

+

+ Categorical Metadata +

{_.map(ranges, (value, key) => { const isColorField = key.includes("color") || key.includes("Color"); const isSelectableCategory = diff --git a/client/src/components/categorical/category.js b/client/src/components/categorical/category.js index 13206e27..976041de 100644 --- a/client/src/components/categorical/category.js +++ b/client/src/components/categorical/category.js @@ -119,34 +119,11 @@ class Category extends React.Component {
-

- { - this.setState({ isExpanded: !isExpanded }); - }} - > - {isExpanded ? : } - - {metadataField} +

+ + {""} + + + { + this.setState({ isExpanded: !isExpanded }); + }} + > + {metadataField} + {isExpanded ? ( + + ) : ( + + )} + + + + +
-
{isExpanded ? this.renderCategoryItems() : null}
+
{isExpanded ? this.renderCategoryItems() : null}
{isExpanded && isTruncated ? (

... truncated list ...

diff --git a/client/src/components/categorical/value.js b/client/src/components/categorical/value.js index 0e3f555c..221fb650 100644 --- a/client/src/components/categorical/value.js +++ b/client/src/components/categorical/value.js @@ -49,42 +49,39 @@ class CategoryValue extends React.Component { style={{ display: "flex", alignItems: "baseline", - justifyContent: "space-between", - fontWeight: selected ? 700 : 400 + justifyContent: "space-between" }} > -

- + + + {value} + +

+ + {count} + - {value} -

-

- {count} -

+
); } diff --git a/client/src/components/continuous/continuous.js b/client/src/components/continuous/continuous.js index 037a0aef..3749586b 100644 --- a/client/src/components/continuous/continuous.js +++ b/client/src/components/continuous/continuous.js @@ -4,6 +4,7 @@ import React from "react"; import _ from "lodash"; import { connect } from "react-redux"; +import * as globals from "../../globals"; import HistogramBrush from "../brushableHistogram"; @@ -48,8 +49,20 @@ class Continuous extends React.Component { } return ( -
- {this.hasContinuous ?

Continuous metadata

: null} +
+ {this.hasContinuous ? ( +

+ Continuous metadata +

+ ) : null} {_.map(ranges, (value, key) => { const isColorField = key.includes("color") || key.includes("Color"); if (value.range && key !== "name" && !isColorField) { diff --git a/client/src/components/continuous/parallelCoordinates.css b/client/src/components/continuous/parallelCoordinates.css index 8e3a4fa0..b2affc9c 100644 --- a/client/src/components/continuous/parallelCoordinates.css +++ b/client/src/components/continuous/parallelCoordinates.css @@ -7,24 +7,24 @@ body { } */ -.parcoords { +:local(.parcoords) { display: block; } -.parcoords svg, -.parcoords canvas { +:local(.parcoords) svg, +:local(.parcoords) canvas { font: 10px sans-serif; position: absolute; } -.parcoords canvas { +:local(.parcoords) canvas { opacity: 0.9; pointer-events: none; } -.axis .title { +:local(.axis .title) { font-size: 10px; - transform: rotate(-21deg) translate(-5px,-6px); + transform: rotate(-21deg) translate(-5px, -6px); fill: #222; cursor: pointer; } @@ -32,14 +32,14 @@ body { /* -webkit-filter: grayscale(100%); filter: grayscale(100%); */ -.axis line, -.axis path { +:local(.axis) line, +:local(.axis) path { fill: none; stroke: #ccc; stroke-width: 1px; } -.axis .tick text { +:local(.axis .tick) text { fill: #222; pointer-events: none; } @@ -52,39 +52,39 @@ old, from reference bl.ocks } */ -.axis:hover line, -.axis:hover path, -.axis.active line, -.axis.active path { +:local(.axis:hover) line, +:local(.axis:hover) path, +:local(.axis.active) line, +:local(.axis.active) path { fill: none; stroke: #222; stroke-width: 1px; } -.axis:hover .title { +:local(.axis:hover .title) { font-weight: bold; } -.axis:hover .tick text { +:local(.axis:hover .tick) text { opacity: 1; } -.axis.active .title { +:local(.axis.active .title) { font-weight: bold; } -.axis.active .tick text { +:local(.axis.active .tick) text { opacity: 1; font-weight: bold; } -.brush .extent { - fill-opacity: .3; +:local(.brush .extent) { + fill-opacity: 0.3; stroke: #fff; stroke-width: 1px; } -.pre { +:local(.pre) { width: 100%; height: 300px; margin: 6px 12px; diff --git a/client/src/components/continuousLegend/index.js b/client/src/components/continuousLegend/index.js index 9fbf0969..68f0d384 100644 --- a/client/src/components/continuousLegend/index.js +++ b/client/src/components/continuousLegend/index.js @@ -6,7 +6,7 @@ import { interpolateViridis } from "d3-scale-chromatic"; // create continuous color legend // http://bl.ocks.org/syntagmatic/e8ccca52559796be775553b467593a9f -const continuous = (selectorId, colorscale) => { +const continuous = (selectorId, colorscale, colorAccessor) => { const legendheight = 200; const legendwidth = 80; const margin = { top: 10, right: 60, bottom: 10, left: 2 }; @@ -84,6 +84,17 @@ const continuous = (selectorId, colorscale) => { `translate(${legendwidth - margin.left - margin.right + 3},${margin.top})` ) .call(legendaxis); + + // text label for the y axis + // svg + // .append("text") + // .attr("transform", "rotate(-90)") + // .attr("y", 3) + // .attr("x", 0 - legendheight / 2) + // .attr("dy", "1em") + // .style("text-anchor", "middle") + // .style("fill", "white") + // .text(colorAccessor); }; @connect(state => ({ @@ -115,7 +126,8 @@ class ContinuousLegend extends React.Component { if (colorScale.range()[0][0] !== "#") { continuous( "#continuous_legend", - d3.scaleSequential(interpolateViridis).domain(colorScale.domain()) + d3.scaleSequential(interpolateViridis).domain(colorScale.domain()), + colorAccessor ); } } diff --git a/client/src/components/expression/cellSetButtons.js b/client/src/components/expression/cellSetButtons.js deleted file mode 100644 index 24cd73e1..00000000 --- a/client/src/components/expression/cellSetButtons.js +++ /dev/null @@ -1,71 +0,0 @@ -// jshint esversion: 6 -import React from "react"; -import _ from "lodash"; -import { connect } from "react-redux"; -import * as globals from "../../globals"; - -@connect() -class CellSetButton extends React.Component { - set() { - const { - differential, - crossfilter, - dispatch, - eitherCellSetOneOrTwo - } = this.props; - - const set = _.map(crossfilter.allFiltered(), "name"); - - if (!differential.diffExp) { - /* diffexp needs to be cleared before we store a new set */ - dispatch({ - type: `store current cell selection as differential set ${eitherCellSetOneOrTwo}`, - data: set - }); - } - } - - render() { - const { differential, eitherCellSetOneOrTwo } = this.props; - const cellListName = `celllist${eitherCellSetOneOrTwo}`; - return ( - - - - ); - } -} - -export default CellSetButton; diff --git a/client/src/components/expression/diffExpHeatmap.js b/client/src/components/expression/diffExpHeatmap.js deleted file mode 100644 index 53810e66..00000000 --- a/client/src/components/expression/diffExpHeatmap.js +++ /dev/null @@ -1,83 +0,0 @@ -// jshint esversion: 6 -import React from "react"; -import _ from "lodash"; -import { connect } from "react-redux"; -import * as d3 from "d3"; -import { interpolateGreys } from "d3-scale-chromatic"; -import HeatmapRow from "./heatmapRow"; - -/********************************** -*********************************** -*********************************** - DiffExp Heatmap -*********************************** -*********************************** -**********************************/ - -@connect(state => ({ - differential: state.differential, - world: state.controls.world -})) -class Heatmap extends React.Component { - render() { - const { world, differential } = this.props; - if (!differential.diffExp) { - return

Select cells & compute differential to see heatmap

; - } - - // summarize the information for display. - const topGenes = _.map(differential.diffExp, val => ({ - varIndex: val[0], - geneName: world.varAnnotations[val[0]].name, - avgDiff: val[1], - set1AvgExp: val[4], - set2AvgExp: val[5] - })); - - // average expression extent - const extent = d3.extent( - _.concat( - _.map(differential.diffExp, val => val[4]), - _.map(differential.diffExp, val => val[5]) - ) - ); - - const greyColorScale = d3 - .scaleSequential() - .domain(extent) - .interpolator(interpolateGreys); - - return ( -
-
-

Gene

-

1

-

2

-

ave diff

-
- {topGenes.map(g => { - const { geneName, avgDiff, set1AvgExp, set2AvgExp } = g; - return ( - - ); - })} -
- ); - } -} - -export default Heatmap; diff --git a/client/src/components/expression/expression.css b/client/src/components/expression/expression.css deleted file mode 100644 index e69de29b..00000000 diff --git a/client/src/components/expression/heatmapRow.js b/client/src/components/expression/heatmapRow.js deleted file mode 100644 index 5e41a6b4..00000000 --- a/client/src/components/expression/heatmapRow.js +++ /dev/null @@ -1,154 +0,0 @@ -import React from "react"; -import { connect } from "react-redux"; -import { FaPaintBrush } from "react-icons/fa"; -import HeatmapSquare from "./heatmapSquare"; -import * as globals from "../../globals"; -import actions from "../../actions"; - -/********************************** -*********************************** -*********************************** - Row -*********************************** -*********************************** -**********************************/ -@connect(state => ({ - scatterplotXXaccessor: state.controls.scatterplotXXaccessor, - scatterplotYYaccessor: state.controls.scatterplotYYaccessor, - colorAccessor: state.controls.colorAccessor -})) -class HeatmapRow extends React.Component { - handleGeneColorScaleClick() { - return () => { - const { dispatch, gene } = this.props; - dispatch(actions.requestSingleGeneExpressionCountsForColoringPOST(gene)); - }; - } - - handleSetGeneAsScatterplotX() { - return () => { - const { dispatch, gene } = this.props; - dispatch({ - type: "set scatterplot x", - data: gene - }); - }; - } - - handleSetGeneAsScatterplotY() { - return () => { - const { dispatch, gene } = this.props; - dispatch({ - type: "set scatterplot y", - data: gene - }); - }; - } - - render() { - const { - gene, - aveDiff, - set1exp, - set2exp, - greyColorScale, - scatterplotXXaccessor, - scatterplotYYaccessor, - colorAccessor - } = this.props; - return ( -
-
- - {gene} - -
- - - - {aveDiff.toFixed(2)} - - - X - - - Y - - - - -
- ); - } -} - -export default HeatmapRow; diff --git a/client/src/components/expression/heatmapSquare.js b/client/src/components/expression/heatmapSquare.js deleted file mode 100644 index 1200b7cb..00000000 --- a/client/src/components/expression/heatmapSquare.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from "react"; -import getContrast from "font-color-contrast"; // https://www.npmjs.com/package/font-color-contrast - -const HeatmapSquare = props => { - const { backgroundColor, text } = props; - const contrastColor = getContrast( - backgroundColor - .substring(4, backgroundColor.length - 1) - .replace(/ /g, "") - .split(",") - ); - return ( -

- {text} -

- ); -}; - -export default HeatmapSquare; diff --git a/client/src/components/framework/buttons.css b/client/src/components/framework/buttons.css index 3f65870a..4e9167bf 100644 --- a/client/src/components/framework/buttons.css +++ b/client/src/components/framework/buttons.css @@ -1,4 +1,4 @@ -.btn { +:local(.btn) { background: none; cursor: pointer; color: "#FFF"; diff --git a/client/src/components/framework/container.css b/client/src/components/framework/container.css index 1338ab8b..2b76dccb 100644 --- a/client/src/components/framework/container.css +++ b/client/src/components/framework/container.css @@ -1,3 +1,3 @@ -.container { +:local(.container) { min-height: 100%; } diff --git a/client/src/components/framework/toasters.js b/client/src/components/framework/toasters.js new file mode 100644 index 00000000..1a8237dc --- /dev/null +++ b/client/src/components/framework/toasters.js @@ -0,0 +1,12 @@ +import { Position, Toaster, Intent } from "@blueprintjs/core"; + +/** Singleton toaster instance. Create separate instances for different options. */ +export const ErrorToastTopCenter = Toaster.create({ + className: "recipe-toaster", + position: Position.TOP, + intent: Intent.WARNING +}); + +export default { + ErrorToastTopCenter +}; diff --git a/client/src/components/geneExpression/cellSetButtons.js b/client/src/components/geneExpression/cellSetButtons.js new file mode 100644 index 00000000..56e45acb --- /dev/null +++ b/client/src/components/geneExpression/cellSetButtons.js @@ -0,0 +1,46 @@ +// jshint esversion: 6 +import React from "react"; +import _ from "lodash"; +import { Button } from "@blueprintjs/core"; +import { connect } from "react-redux"; +import * as globals from "../../globals"; + +@connect() +class CellSetButton extends React.Component { + set() { + const { + differential, + crossfilter, + dispatch, + eitherCellSetOneOrTwo + } = this.props; + + const set = _.map(crossfilter.allFiltered(), "name"); + + if (!differential.diffExp) { + /* diffexp needs to be cleared before we store a new set */ + dispatch({ + type: `store current cell selection as differential set ${eitherCellSetOneOrTwo}`, + data: set + }); + } + } + + render() { + const { differential, eitherCellSetOneOrTwo } = this.props; + const cellListName = `celllist${eitherCellSetOneOrTwo}`; + return ( + + + + ); + } +} + +export default CellSetButton; diff --git a/client/src/components/expression/expressionButtons.js b/client/src/components/geneExpression/expressionButtons.js similarity index 58% rename from client/src/components/expression/expressionButtons.js rename to client/src/components/geneExpression/expressionButtons.js index 9d6c040f..a77dfe1e 100644 --- a/client/src/components/expression/expressionButtons.js +++ b/client/src/components/geneExpression/expressionButtons.js @@ -1,6 +1,7 @@ // jshint esversion: 6 import React from "react"; import _ from "lodash"; +import { Button } from "@blueprintjs/core"; import { connect } from "react-redux"; import * as globals from "../../globals"; import actions from "../../actions"; @@ -43,58 +44,32 @@ class Expression extends React.Component { if (!differential) { return null; } + const haveBothCellSets = + !!differential.celllist1 && !!differential.celllist2; return (
{!differential.diffExp ? ( - + Compute Differential Expression + ) : null} {differential.diffExp ? ( - + Clear Differential Expression + ) : null}
); diff --git a/client/src/components/geneExpression/index.js b/client/src/components/geneExpression/index.js index d0252a84..7d44b97a 100644 --- a/client/src/components/geneExpression/index.js +++ b/client/src/components/geneExpression/index.js @@ -5,10 +5,11 @@ import React from "react"; import _ from "lodash"; import * as d3 from "d3"; import { connect } from "react-redux"; -import { FaPlusCircle } from "react-icons/fa"; import HistogramBrush from "../brushableHistogram"; import * as globals from "../../globals"; import actions from "../../actions"; +import { ErrorToastTopCenter } from "../framework/toasters"; +import ExpressionButtons from "./expressionButtons"; @connect(state => { const metadata = _.get(state.controls.world, "obsAnnotations", null); @@ -45,13 +46,18 @@ class GeneExpression extends React.Component { const { gene } = this.state; if (userDefinedGenes.indexOf(gene) !== -1) { - console.log("That gene already exists"); + ErrorToastTopCenter.show({ + message: "That gene already exists" + }); } else if (userDefinedGenes.length > 15) { - console.log( - "That's too many genes, you can have at most 15 user defined genes" - ); + ErrorToastTopCenter.show({ + message: + "That's too many genes, you can have at most 15 user defined genes" + }); } else if (!_.find(world.varAnnotations, { name: gene })) { - console.log("That doesn't appear to be a valid gene name."); + ErrorToastTopCenter.show({ + message: "That doesn't appear to be a valid gene name." + }); } else { dispatch(actions.requestUserDefinedGene(gene)); dispatch({ @@ -68,79 +74,88 @@ class GeneExpression extends React.Component { return (
- { - this.setState({ gene: e.target.value }); - }} - type="text" - value={gene} - /> - - {world && userDefinedGenes.length > 0 ? ( -

User defined genes

- ) : null} - {world && userDefinedGenes.length > 0 - ? _.map(userDefinedGenes, geneName => { - const values = world.varDataCache[geneName]; - if (!values) { - return null; - } - return ( - - ); - }) - : null} - {differential.diffExp ?

Differentially Expressed Genes

: null} - {differential.diffExp - ? _.map(differential.diffExp, value => { - const annotations = world.varAnnotations[value[0]]; - const { name } = annotations; - const values = world.varDataCache[name]; - if (!values) { - return null; - } - return ( - - ); - }) - : null} +

Custom genes

+
+
+ + { + this.setState({ gene: e.target.value }); + }} + value={gene} + type="text" + className="bp3-input" + placeholder="Add a custom gene" + style={{ paddingRight: 94 }} + /> +
+ +
+ {world && userDefinedGenes.length > 0 + ? _.map(userDefinedGenes, geneName => { + const values = world.varDataCache[geneName]; + if (!values) { + return null; + } + return ( + + ); + }) + : null} +
+
+

+ Differentially Expressed Genes +

+ + {differential.diffExp + ? _.map(differential.diffExp, value => { + const annotations = world.varAnnotations[value[0]]; + const { name } = annotations; + const values = world.varDataCache[name]; + if (!values) { + return null; + } + return ( + + ); + }) + : null} +
); } diff --git a/client/src/components/graph/graph.css b/client/src/components/graph/graph.css index 7c207756..e0bebaa2 100644 --- a/client/src/components/graph/graph.css +++ b/client/src/components/graph/graph.css @@ -1,4 +1,4 @@ -.graphCanvas path { +:local(.graphCanvas) path { shape-rendering: crispEdges; } @@ -16,8 +16,8 @@ pointer-events: none; } -.axis path, -.axis line { +:local(.axis) path, +:local(.axis) line { fill: none; stroke: #000; stroke-width: 1px; @@ -29,6 +29,6 @@ circle { fill: none; } -.hidden { +:local(.hidden) { display: none; } diff --git a/client/src/components/graph/graph.js b/client/src/components/graph/graph.js index b63553ba..0cf19c33 100644 --- a/client/src/components/graph/graph.js +++ b/client/src/components/graph/graph.js @@ -5,10 +5,8 @@ import * as d3 from "d3"; import { connect } from "react-redux"; import mat4 from "gl-mat4"; import _regl from "regl"; +import { Button } from "@blueprintjs/core"; -import { FaCrosshairs, FaSearchPlus } from "react-icons/fa"; - -import * as globals from "../../globals"; import setupSVGandBrushElements from "./setupSVGandBrush"; import actions from "../../actions"; import _camera from "../../util/camera"; @@ -340,91 +338,48 @@ class Graph extends React.Component { alignItems: "baseline" }} > - - +
- - - - + /> +
diff --git a/client/src/components/leftsidebar.js b/client/src/components/leftsidebar.js index 4f9cbbc7..346b2fb1 100644 --- a/client/src/components/leftsidebar.js +++ b/client/src/components/leftsidebar.js @@ -5,8 +5,6 @@ import { connect } from "react-redux"; import Categorical from "./categorical/categorical"; import Continuous from "./continuous/continuous"; import GeneExpression from "./geneExpression"; -import ExpressionButtons from "./expression/expressionButtons"; -import Heatmap from "./expression/diffExpHeatmap"; import * as globals from "../globals"; import DynamicScatterplot from "./scatterplot/scatterplot"; @@ -37,30 +35,36 @@ class LeftSideBar extends React.Component { this magic number should be made less fragile, if cellxgene logo or tabs change, this must as well */ - const metadataSectionPadding = - scatterplotXXaccessor && scatterplotYYaccessor ? 450 : 0; + const metadataSectionPadding = 0; + // scatterplotXXaccessor && scatterplotYYaccessor ? 450 : 0; + return ( -
+

- cellxgene:   - {datasetTitle} + cellxgene: {datasetTitle}

+
-
- {scatterplotXXaccessor && scatterplotYYaccessor ? ( - - ) : null} -
-
- {currentTab === "metadata" ? : null} -
+ {scatterplotXXaccessor && scatterplotYYaccessor ? ( + + ) : null}
); } diff --git a/client/src/components/scatterplot/scatterplot.css b/client/src/components/scatterplot/scatterplot.css index b567ed53..dab91e0a 100644 --- a/client/src/components/scatterplot/scatterplot.css +++ b/client/src/components/scatterplot/scatterplot.css @@ -1,15 +1,14 @@ - -.scatterplot { +:local(.scatterplot) { display: block; } -.scatterplot svg, -.scatterplot canvas { +:local(.scatterplot) svg, +:local(.scatterplot) canvas { font: 10px sans-serif; position: absolute; } -.scatterplot canvas { +:local(.scatterplot) canvas { opacity: 0.9; pointer-events: none; } diff --git a/client/src/components/scatterplot/scatterplot.js b/client/src/components/scatterplot/scatterplot.js index 5985fe12..6dfc67df 100644 --- a/client/src/components/scatterplot/scatterplot.js +++ b/client/src/components/scatterplot/scatterplot.js @@ -5,8 +5,10 @@ import React from "react"; import _ from "lodash"; import { connect } from "react-redux"; +import { Button, ButtonGroup } from "@blueprintjs/core"; import _regl from "regl"; import * as d3 from "d3"; +import * as globals from "../../globals"; import _camera from "../../util/camera"; @@ -64,6 +66,7 @@ class Scatterplot extends React.Component { this.axes = false; this.state = { svg: null, + minimized: null, xScale: null, yScale: null }; @@ -267,14 +270,48 @@ class Scatterplot extends React.Component { } render() { + const { dispatch } = this.props; + const { minimized } = this.state; + return (
+ +