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 @@
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 ?
... 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} -
+ ); } 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 ( -Continuous metadata
: null} ++ 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) { - returnSelect 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
-- {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 (User defined genes
- ) : null} - {world && userDefinedGenes.length > 0 - ? _.map(userDefinedGenes, geneName => { - const values = world.varDataCache[geneName]; - if (!values) { - return null; - } - return ( -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 ( -Custom genes
++ Differentially Expressed Genes +
+- cellxgene: - {datasetTitle} + cellxgene: {datasetTitle}
+