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
This commit is contained in:
Colin Megill
2018-10-22 15:46:37 -04:00
committed by GitHub
parent 0c271bc815
commit df671192be
34 changed files with 717 additions and 737 deletions

View File

@@ -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)(\?.*)?$/,

View File

@@ -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
}
};

View File

@@ -6,9 +6,9 @@
<title>cellxgene</title>
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,400i,700" rel="stylesheet">
<style>
html, body, p, h1, h2, h3, h4, h5, h6, span, button, input, text {
html, body, p, h1, h2, h3, h4, h5, h6, span, button, input, label, text {
font-family: 'Roboto Condensed','Helvetica Neue','Helvetica','Arial',sans-serif;
font-size: 16px;
font-size: 14px;
}
body {
margin: 0;

View File

@@ -4,10 +4,19 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>cellxgene</title>
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,400i,700" rel="stylesheet">
<style>
html, body, p, h1, h2, h3, h4, h5, h6, span, button, input {
font-family: Helvetica Neue,Helvetica,Arial,sans-serif;
font-size: 16px;
html, body, p, h1, h2, h3, h4, h5, h6, span, button, input, label, text {
font-family: 'Roboto Condensed','Helvetica Neue','Helvetica','Arial',sans-serif;
font-size: 14px;
}
body {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box;
}
</style>
</head>

271
client/package-lock.json generated
View File

@@ -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": {

View File

@@ -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",

View File

@@ -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 {
}}
>
<strong>1:</strong>
{` ${diffExp_set1AvgExp.toPrecision(2)}`}
{` ${set1AvgExp.toPrecision(2)}`}
</span>
<span
style={{
@@ -280,7 +280,7 @@ class HistogramBrush extends React.Component {
}}
>
<strong>2:</strong>
{` ${diffExp_set2AvgExp.toPrecision(2)}`}
{` ${set2AvgExp.toPrecision(2)}`}
</span>
<span
style={{
@@ -288,7 +288,7 @@ class HistogramBrush extends React.Component {
marginLeft: 7
}}
>
{`Av. Diff: ${diffExp_avgDiff.toFixed(2)}`}
{`Av. Diff: ${avgDiff.toFixed(2)}`}
</span>
<span
onClick={this.handleSetGeneAsScatterplotX(field).bind(this)}

View File

@@ -2,6 +2,7 @@
import React from "react";
import _ from "lodash";
import { connect } from "react-redux";
import * as globals from "../../globals";
import * as globals from "../../globals";
import Category from "./category";
@@ -38,13 +39,16 @@ class Categories extends React.Component {
return (
<div
style={{
width: 310,
marginRight: 40,
paddingRight: 20,
flexShrink: 0
padding: globals.leftSidebarSectionPadding
}}
>
<p> Categorical Metadata </p>
<p
style={Object.assign({}, globals.leftSidebarSectionHeading, {
marginTop: 4
})}
>
Categorical Metadata
</p>
{_.map(ranges, (value, key) => {
const isColorField = key.includes("color") || key.includes("Color");
const isSelectableCategory =

View File

@@ -119,34 +119,11 @@ class Category extends React.Component {
<div
style={{
display: "flex",
justifyContent: "space-between",
justifyContent: "flex-start",
alignItems: "baseline"
}}
>
<p
style={{
// flexShrink: 0,
fontWeight: 500,
// textAlign: "right",
// fontFamily: globals.accentFont,
// fontStyle: "italic",
margin: "3px 10px 3px 0px"
}}
>
<span
style={{
cursor: "pointer",
display: "inline-block",
position: "relative",
top: 2
}}
onClick={() => {
this.setState({ isExpanded: !isExpanded });
}}
>
{isExpanded ? <FaChevronDown /> : <FaChevronRight />}
</span>
{metadataField}
<label className="bp3-control bp3-checkbox">
<input
onChange={this.handleToggleAllClick.bind(this)}
ref={el => {
@@ -156,29 +133,41 @@ class Category extends React.Component {
checked={isChecked}
type="checkbox"
/>
<span
onClick={this.handleColorChange.bind(this)}
style={{
fontSize: 14,
marginLeft: 4,
// padding: this.props.colorAccessor === this.props.metadataField ? 3 : "auto",
borderRadius: 3,
color:
colorAccessor === metadataField
? globals.brightBlue
: "black",
// backgroundColor: this.props.colorAccessor === this.props.metadataField ? globals.brightBlue : "inherit",
display: "inline-block",
position: "relative",
top: 2,
cursor: "pointer"
}}
>
<FaPaintBrush />
</span>
</p>
<span className="bp3-control-indicator" />
{""}
</label>
<span
style={{
cursor: "pointer",
display: "inline-block"
}}
onClick={() => {
this.setState({ isExpanded: !isExpanded });
}}
>
{metadataField}
{isExpanded ? (
<FaChevronDown style={{ fontSize: 10, marginLeft: 5 }} />
) : (
<FaChevronRight style={{ fontSize: 10, marginLeft: 5 }} />
)}
</span>
<span
onClick={this.handleColorChange.bind(this)}
style={{
marginLeft: 4,
color:
colorAccessor === metadataField ? globals.brightBlue : "black",
display: "inline-block",
cursor: "pointer"
}}
>
<FaPaintBrush style={{ fontSize: 12, marginLeft: 10 }} />
</span>
</div>
<div>{isExpanded ? this.renderCategoryItems() : null}</div>
<div style={{ marginLeft: 26 }}>{isExpanded ? this.renderCategoryItems() : null}</div>
<div>
{isExpanded && isTruncated ? (
<p style={{ paddingLeft: 15 }}>... truncated list ...</p>

View File

@@ -49,42 +49,39 @@ class CategoryValue extends React.Component {
style={{
display: "flex",
alignItems: "baseline",
justifyContent: "space-between",
fontWeight: selected ? 700 : 400
justifyContent: "space-between"
}}
>
<p
<div
style={{
paddingLeft: 15,
width: 200,
flexShrink: 0,
margin: 0
// lineHeight: "1em"
margin: 0,
padding: 0,
userSelect: "none"
}}
>
<input
style={{ position: "relative", top: 1 }}
onChange={
selected ? this.toggleOff.bind(this) : this.toggleOn.bind(this)
}
checked={selected}
type="checkbox"
<label className="bp3-control bp3-checkbox">
<input
onChange={
selected ? this.toggleOff.bind(this) : this.toggleOn.bind(this)
}
checked={selected}
type="checkbox"
/>
<span className="bp3-control-indicator" />
{value}
</label>
</div>
<span>
<span>{count}</span>
<svg
style={{
marginLeft: 5,
width: 11,
height: 11,
backgroundColor: c ? colorScale(value) : "inherit"
}}
/>
{value}
</p>
<p
style={{
padding: "1px 10px",
width: 80,
textAlign: "center",
backgroundColor: c ? colorScale(value) : "inherit",
color: c ? "white" : "black",
margin: 0
// lineHeight: "1em"
}}
>
{count}
</p>
</span>
</div>
);
}

View File

@@ -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 (
<div>
{this.hasContinuous ? <p> Continuous metadata </p> : null}
<div
style={{
padding: globals.leftSidebarSectionPadding
}}
>
{this.hasContinuous ? (
<p
style={Object.assign({}, globals.leftSidebarSectionHeading, {
marginTop: 40
})}
>
Continuous metadata
</p>
) : null}
{_.map(ranges, (value, key) => {
const isColorField = key.includes("color") || key.includes("Color");
if (value.range && key !== "name" && !isColorField) {

View File

@@ -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;

View File

@@ -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
);
}
}

View File

@@ -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 (
<span style={{ marginRight: 10 }}>
<button
type="button"
style={{
color: "#FFF",
borderRadius: 2,
padding: "0px 10px",
height: 30,
backgroundColor: !differential.diffExp
? globals.brightBlue
: globals.lightGrey,
border: "none",
cursor: "pointer"
}}
onClick={this.set.bind(this)}
>
<span style={{ fontSize: 14, fontWeight: 700 }}>
{" "}
{eitherCellSetOneOrTwo}
{": "}
</span>
<span
style={{
fontSize: 14,
marginLeft: 8,
position: "relative",
top: 0
}}
>
{differential[cellListName]
? `${differential[cellListName].length} cells`
: "0 cells"}
</span>
</button>
</span>
);
}
}
export default CellSetButton;

View File

@@ -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 <p>Select cells & compute differential to see heatmap</p>;
}
// 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 (
<div>
<div
style={{
display: "flex",
justifyContent: "flex-start",
width: 400,
fontWeight: 700
}}
>
<p style={{ marginRight: 110 }}>Gene</p>
<p style={{ marginRight: 25 }}>1</p>
<p style={{ marginRight: 20 }}>2</p>
<p>ave diff</p>
</div>
{topGenes.map(g => {
const { geneName, avgDiff, set1AvgExp, set2AvgExp } = g;
return (
<HeatmapRow
key={geneName}
gene={geneName}
greyColorScale={greyColorScale}
aveDiff={avgDiff}
set1exp={set1AvgExp}
set2exp={set2AvgExp}
/>
);
})}
</div>
);
}
}
export default Heatmap;

View File

@@ -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 (
<div
style={{
width: 220,
display: "flex",
justifyContent: "flex-start",
alignItems: "baseline"
}}
>
<div style={{ width: 150, flexShrink: 0 }}>
<span
style={{
fontSize: 14
}}
>
{gene}
</span>
</div>
<HeatmapSquare
backgroundColor={greyColorScale(set1exp)}
text={set1exp.toPrecision(2)}
/>
<HeatmapSquare
backgroundColor={greyColorScale(set2exp)}
text={set2exp.toPrecision(2)}
/>
<span
title={aveDiff}
style={{
fontSize: 12,
marginLeft: 10,
marginRight: 10
}}
>
{aveDiff.toFixed(2)}
</span>
<span
onClick={this.handleSetGeneAsScatterplotX(gene).bind(this)}
style={{
fontSize: 16,
color:
scatterplotXXaccessor === gene ? "white" : globals.brightBlue,
cursor: "pointer",
position: "relative",
top: 1,
fontWeight: 700,
marginRight: 4,
borderRadius: 3,
padding: "2px 3px",
backgroundColor:
scatterplotXXaccessor === gene ? globals.brightBlue : "inherit"
}}
>
X
</span>
<span
onClick={this.handleSetGeneAsScatterplotY(gene).bind(this)}
style={{
fontSize: 16,
color:
scatterplotYYaccessor === gene ? "white" : globals.brightBlue,
cursor: "pointer",
position: "relative",
top: 1,
fontWeight: 700,
marginRight: 4,
borderRadius: 3,
padding: "2px 3px",
backgroundColor:
scatterplotYYaccessor === gene ? globals.brightBlue : "inherit"
}}
>
Y
</span>
<span
onClick={this.handleGeneColorScaleClick(gene).bind(this)}
style={{
fontSize: 16,
cursor: "pointer",
position: "relative",
marginRight: 6,
borderRadius: 3,
padding: "0px 2px 2px 2px",
color: colorAccessor === gene ? "white" : "inherit",
backgroundColor:
colorAccessor === gene ? globals.brightBlue : "inherit"
}}
>
<FaPaintBrush style={{ display: "inline-block" }} />
</span>
</div>
);
}
}
export default HeatmapRow;

View File

@@ -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 (
<p
style={{
padding: "12px 6px",
textAlign: "center",
color: contrastColor,
width: 40,
flexShrink: 0,
fontSize: 12,
margin: 0,
backgroundColor
}}
>
{text}
</p>
);
};
export default HeatmapSquare;

View File

@@ -1,4 +1,4 @@
.btn {
:local(.btn) {
background: none;
cursor: pointer;
color: "#FFF";

View File

@@ -1,3 +1,3 @@
.container {
:local(.container) {
min-height: 100%;
}

View File

@@ -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
};

View File

@@ -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 (
<span style={{ marginRight: 10 }}>
<Button type="button" onClick={this.set.bind(this)}>
{eitherCellSetOneOrTwo}
{": "}
{differential[cellListName]
? `${differential[cellListName].length} cells`
: "0 cells"}
</Button>
</span>
);
}
}
export default CellSetButton;

View File

@@ -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 (
<div style={{ marginRight: 10, marginBottom: 10 }}>
<CellSetButton {...this.props} eitherCellSetOneOrTwo={1} />
<CellSetButton {...this.props} eitherCellSetOneOrTwo={2} />
{!differential.diffExp ? (
<button
<Button
style={{ marginTop: 10 }}
disabled={!haveBothCellSets}
intent="primary"
type="button"
style={{
fontSize: 14,
fontWeight: 400,
color: "#FFF",
padding: "0px 10px",
height: 30,
borderRadius: 2,
backgroundColor:
differential.celllist1 && differential.celllist2
? globals.brightBlue
: globals.lightGrey,
border: "none",
cursor:
differential.celllist1 && differential.celllist2
? "pointer"
: "auto"
}}
onClick={this.computeDiffExp.bind(this)}
>
{" "}
Compute Differential Expression{" "}
</button>
Compute Differential Expression
</Button>
) : null}
{differential.diffExp ? (
<button
<Button
type="button"
style={{
fontSize: 14,
fontWeight: 400,
color: "#FFF",
padding: "0px 10px",
height: 30,
borderRadius: 2,
backgroundColor: globals.brightBlue,
border: "none",
cursor:
differential.celllist1 && differential.celllist2
? "pointer"
: "auto"
}}
style={{ marginTop: 10 }}
intent="warning"
onClick={this.clearDifferentialExpression.bind(this)}
>
{" "}
Clear Differential Expression{" "}
</button>
Clear Differential Expression
</Button>
) : null}
</div>
);

View File

@@ -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 (
<div>
<input
onKeyDown={this.keyPress.bind(this)}
onChange={e => {
this.setState({ gene: e.target.value });
}}
type="text"
value={gene}
/>
<button
type="button"
<div
style={{
border: "none",
background: "none",
cursor: "pointer",
outline: "none",
marginTop: 20,
padding: 0
padding: globals.leftSidebarSectionPadding,
marginTop: 30
}}
onClick={this.handleClick.bind(this)}
>
<FaPlusCircle
style={{
display: "inline-block",
marginLeft: 7,
position: "relative",
top: 5,
color: globals.brightBlue,
fontSize: 22
}}
/>{" "}
add gene{" "}
</button>
{world && userDefinedGenes.length > 0 ? (
<p>User defined genes</p>
) : null}
{world && userDefinedGenes.length > 0
? _.map(userDefinedGenes, geneName => {
const values = world.varDataCache[geneName];
if (!values) {
return null;
}
return (
<HistogramBrush
key={geneName}
field={geneName}
ranges={d3.extent(values)}
isUserDefined
/>
);
})
: null}
{differential.diffExp ? <p> Differentially Expressed Genes </p> : 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 (
<HistogramBrush
key={name}
field={name}
ranges={d3.extent(values)}
isDiffExp
diffExp_avgDiff={value[1]}
diffExp_set1AvgExp={value[4]}
diffExp_set2AvgExp={value[5]}
/>
);
})
: null}
<p style={globals.leftSidebarSectionHeading}>Custom genes</p>
<div style={{ marginTop: 11 }} className="bp3-control-group">
<div className="bp3-input-group">
<span className="bp3-icon bp3-icon-symbol-cross" />
<input
onKeyDown={this.keyPress.bind(this)}
onChange={e => {
this.setState({ gene: e.target.value });
}}
value={gene}
type="text"
className="bp3-input"
placeholder="Add a custom gene"
style={{ paddingRight: 94 }}
/>
</div>
<button
type="button"
className="bp3-button bp3-intent-primary"
onClick={this.handleClick.bind(this)}
>
Add
</button>
</div>
{world && userDefinedGenes.length > 0
? _.map(userDefinedGenes, geneName => {
const values = world.varDataCache[geneName];
if (!values) {
return null;
}
return (
<HistogramBrush
key={geneName}
field={geneName}
ranges={d3.extent(values)}
isUserDefined
/>
);
})
: null}
</div>
<div
style={{
padding: globals.leftSidebarSectionPadding
}}
>
<p
style={Object.assign({}, globals.leftSidebarSectionHeading, {
marginTop: 40
})}
>
Differentially Expressed Genes
</p>
<ExpressionButtons />
{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 (
<HistogramBrush
key={name}
field={name}
ranges={d3.extent(values)}
isDiffExp
avgDiff={value[1]}
set1AvgExp={value[4]}
set2AvgExp={value[5]}
/>
);
})
: null}
</div>
</div>
);
}

View File

@@ -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;
}

View File

@@ -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"
}}
>
<button
<Button
type="button"
style={{ marginRight: 10 }}
onClick={() => {
dispatch(actions.resetGraph());
}}
style={{
fontSize: 14,
fontWeight: 400,
color: "white",
padding: "0px 10px",
height: 30,
marginRight: 10,
borderRadius: 2,
backgroundColor: globals.brightBlue,
border: "none",
cursor: "pointer"
}}
>
reset graph
</button>
<button
</Button>
<Button
type="button"
style={{ marginRight: 10 }}
onClick={() => {
dispatch(actions.regraph());
}}
style={{
fontSize: 14,
fontWeight: 400,
color: "white",
padding: "0px 10px",
height: 30,
marginRight: 10,
borderRadius: 2,
backgroundColor: globals.brightBlue,
border: "none",
cursor: "pointer"
}}
>
regraph selection
</button>
</Button>
<div>
<span>
<button
<div className="bp3-button-group">
<Button
className="bp3-button bp3-icon-locate"
type="button"
active={mode === "brush"}
onClick={() => {
this.setState({ mode: "brush" });
}}
style={{
cursor: "pointer",
border:
mode === "brush" ? "1px solid black" : "1px solid white",
backgroundColor: "white",
padding: "5px 5px 2px 5px",
position: "relative",
top: 2,
marginRight: 10,
borderRadius: 3
}}
>
{" "}
<FaCrosshairs />{" "}
</button>
<button
/>
<Button
type="button"
className="bp3-button bp3-icon-zoom-in"
active={mode === "zoom"}
onClick={() => {
this.handleBrushDeselectAction();
this.restartReglLoop();
this.setState({ mode: "zoom" });
}}
style={{
cursor: "pointer",
border:
mode === "zoom" ? "1px solid black" : "1px solid white",
backgroundColor: "white",
padding: "5px 5px 2px 5px",
position: "relative",
top: 2,
marginRight: 10,
borderRadius: 3
cursor: "pointer"
}}
>
{" "}
<FaSearchPlus />{" "}
</button>
</span>
/>
</div>
</div>
</div>
</div>

View File

@@ -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 (
<div style={{ position: "fixed" }}>
<div
style={{
position: "fixed",
backgroundColor: "white",
/* x y blur spread color */
boxShadow: "1px 0px 6px 2px rgba(153,153,153,0.4)"
}}
>
<p
style={{
position: "fixed",
left: responsive.width / 2,
top: 14,
top: globals.cellxgeneTitleTopPadding,
left: globals.leftSidebarWidth + globals.cellxgeneTitleLeftPadding,
margin: 0,
fontSize: 24,
fontSize: globals.largestFontSize,
color: globals.darkerGrey,
fontWeight: 700,
width: "100%"
}}
>
cellxgene: &nbsp;
{datasetTitle}
cellxgene: {datasetTitle}
</p>
<div
style={{
height: responsive.height - metadataSectionPadding,
width: 400,
padding: "0px 10px 10px 10px",
width: globals.leftSidebarWidth,
overflowY: "auto",
overflowX: "hidden"
}}
@@ -69,20 +73,9 @@ class LeftSideBar extends React.Component {
<GeneExpression />
<Continuous />
</div>
<div
style={{
position: "fixed",
bottom: 0,
left: 0
}}
>
{scatterplotXXaccessor && scatterplotYYaccessor ? (
<DynamicScatterplot />
) : null}
</div>
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{currentTab === "metadata" ? <ExpressionButtons /> : null}
</div>
{scatterplotXXaccessor && scatterplotYYaccessor ? (
<DynamicScatterplot />
) : null}
</div>
);
}

View File

@@ -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;
}

View File

@@ -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 (
<div
style={{
backgroundColor: "white",
paddingBottom: 20
position: "fixed",
bottom: minimized ? -height + -margin.top : 0,
left: globals.leftSidebarWidth + globals.scatterplotPaddingLeft,
paddingBottom: 20,
backgroundColor: "white"
}}
id="scatterplot_wrapper"
>
<ButtonGroup
minimal
style={{
position: "absolute",
right: 5,
top: 5
}}
>
<Button
type="button"
icon={minimized ? "plus" : "minus"}
onClick={() => {
this.setState({ minimized: !minimized });
}}
/>
<Button
type="button"
icon="cross"
onClick={() => {
dispatch({
type: "clear scatterplot"
});
dispatch({
type: "reset colorscale"
});
}}
/>
</ButtonGroup>
<div
className={styles.scatterplot}
id="scatterplot"

View File

@@ -1,5 +1,5 @@
// jshint esversion: 6
export const margin = { top: 66, right: 110, bottom: 20, left: 60 };
export const margin = { top: 40, right: 5, bottom: 20, left: 60 };
export const width = 340;
export const height = 340 - margin.top - margin.bottom;
export const innerHeight = height - 2;

View File

@@ -46,6 +46,7 @@ export const configDefaults = {
/* colors */
export const blue = "#4a90e2";
export const hcaBlue = "#1c7cc7";
export const lightestGrey = "rgb(249,249,249)";
export const lighterGrey = "rgb(245,245,245)";
export const lightGrey = "rgb(211,211,211)";
export const mediumGrey = "rgb(153,153,153)";
@@ -58,9 +59,35 @@ export const darkGreen = "#448C4D";
export const defaultCellColor = "rgb(0,0,0,1)";
export const tiniestFontSize = 12;
/* typography constants */
export const tiniestFontSize = 12;
export const largestFontSize = 24;
export const uppercaseLetterSpacing = "0.04em";
export const bolder = 700;
export const accentFont = "Georgia,Times,Times New Roman,serif";
export const maxParagraphWidth = 600;
/* layout styles constants */
export const cellxgeneTitleLeftPadding = 14;
export const cellxgeneTitleTopPadding = 7;
export const maxControlsWidth = 800;
export const graphMargin = { top: 20, right: 10, bottom: 30, left: 40 };
export const graphWidth = 700;
export const graphHeight = 700;
export const scatterplotPaddingLeft = 14;
export const leftSidebarWidth = 365;
export const leftSidebarSectionHeading = {
fontSize: 18,
textTransform: "uppercase",
fontWeight: 500,
letterSpacing: ".05em"
};
export const leftSidebarSectionPadding = 10;
let _API = {
// prefix: "http://api.clustering.czi.technology/api/",
@@ -73,14 +100,6 @@ let _API = {
if (window.CELLXGENE && window.CELLXGENE.API) _API = window.CELLXGENE.API;
export const API = _API;
export const accentFont = "Georgia,Times,Times New Roman,serif";
export const maxParagraphWidth = 600;
export const maxControlsWidth = 800;
export const graphMargin = { top: 20, right: 10, bottom: 30, left: 40 };
export const graphWidth = 700;
export const graphHeight = 700;
export const ordinalColors = [
"#0ac115",
"#c10ab6",

View File

@@ -0,0 +1,9 @@
/*
>>>GLOBAL<<< CSS imports & definitions
Do NOT put anything in this file that is not global. We do not perform
namespace mangling on these definitions. See webpack config for specifics.
*/
@import "~@blueprintjs/core/lib/css/blueprint.css";
@import "~@blueprintjs/icons/lib/css/blueprint-icons.css";
@import "~@blueprintjs/select/lib/css/blueprint-select.css";

View File

@@ -4,6 +4,8 @@ import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import "./index.css";
/* our code */
import App from "./components/app";
import store from "./reducers";

View File

@@ -516,6 +516,12 @@ const Controls = (
...state,
scatterplotYYaccessor: action.data
};
case "clear scatterplot":
return {
...state,
scatterplotXXaccessor: null,
scatterplotYYaccessor: null
};
default:
return state;