mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-22 20:38:12 +08:00
initial commit
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import * as globals from "../../globals";
|
||||
|
||||
import cells from "../../../data/GBM_metadata.js";
|
||||
import createCategoryCounts from "./createCategoryCounts";
|
||||
|
||||
const Button = ({category, c, i}) => (
|
||||
<button
|
||||
key={i}
|
||||
style={{
|
||||
border: i === 0 ? "none" : `1px solid ${globals.lightgrey}`,
|
||||
background: i === 0 ? globals.hcaBlue : "none",
|
||||
color: i === 0 ? "white" : "black",
|
||||
padding: "7px 10px",
|
||||
marginRight: 20,
|
||||
borderRadius: 3,
|
||||
cursor: "pointer"
|
||||
}}>
|
||||
{c}
|
||||
<span
|
||||
style={{
|
||||
fontWeight: i === 0 ? globals.bolder : "auto",
|
||||
background: i === 0 ? "white" : "none",
|
||||
color: "black",
|
||||
marginLeft: 10,
|
||||
padding: "2px 4px",
|
||||
borderRadius: 3
|
||||
}}>
|
||||
{category[c]}
|
||||
</span>
|
||||
</button>
|
||||
)
|
||||
|
||||
const Category = ({category, title}) => (
|
||||
<div>
|
||||
<p>{title}</p>
|
||||
{ _.map(Object.keys(category), (c, i) => <Button key={i} category={category} c={c} i={i} />) }
|
||||
</div>
|
||||
)
|
||||
|
||||
const Categorical = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>Categorical Metadata</h3>
|
||||
{
|
||||
_.map(createCategoryCounts(cells),
|
||||
(value, key) => {
|
||||
return <Category key={key} title={key} category={value} />
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default Categorical;
|
||||
|
||||
/*
|
||||
|
||||
[on off] toggle hide deselected filters (shows a menu vs shows what you ordered in compact/narrative form. fold out animation.)
|
||||
|
||||
<p> <button> Field name [initial state] [create 2d graph] [explain part of 2d graph] </button> </p>
|
||||
<p> <button> Field name [initial state] [create hypothesis] [validate hypothesis] </button> </p>
|
||||
<p> <button> Field name [total] [selected in current filters] [selected in graph selection] </button> </p>
|
||||
<p> <button> Tumor [400] [40] [4] </button> </p>
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,45 @@
|
||||
import * as globals from "../../globals.js"
|
||||
|
||||
/*
|
||||
end result:
|
||||
|
||||
counts: {
|
||||
Sample.type: {
|
||||
glioblastoma: 3452
|
||||
},
|
||||
Selection: {
|
||||
foo: 234,
|
||||
bar: 21
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
const categories = globals.categories;
|
||||
|
||||
const createCategoryCounts = (cells) => {
|
||||
|
||||
/* instantiate counts obj */
|
||||
const counts = {};
|
||||
|
||||
categories.forEach((category) => {
|
||||
counts[category] = {};
|
||||
})
|
||||
|
||||
cells.forEach((cell) => {
|
||||
categories.forEach((category) => {
|
||||
|
||||
/* if, for the given category (ie., categories.Location), we do not have ie., glioblastoma already, create it. Otherwise increment it. */
|
||||
if (!counts[category][cell[category]]) {
|
||||
counts[category][cell[category]] = 1;
|
||||
} else {
|
||||
counts[category][cell[category]]++
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
return counts;
|
||||
}
|
||||
|
||||
export default createCategoryCounts;
|
||||
@@ -0,0 +1,5 @@
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
min-height: 100%;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
import styles from './container.css';
|
||||
|
||||
const Container = props => (
|
||||
<div className={styles.container}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Container;
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import _ from "lodash";
|
||||
import cells from "../../../data/GBM_metadata.js";
|
||||
import drawParallelCoordinates from "./drawParallelCoordinates";
|
||||
import createContinuousRanges from "./createContinuousRanges";
|
||||
|
||||
const Continuous = () => {
|
||||
|
||||
drawParallelCoordinates(cells)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3> Continuous Metadata </h3>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default Continuous;
|
||||
@@ -0,0 +1,25 @@
|
||||
import * as globals from "../../globals.js"
|
||||
|
||||
/*
|
||||
end result:
|
||||
|
||||
ranges: {
|
||||
Total_reads: {
|
||||
min: 11111,
|
||||
max: 33333
|
||||
},
|
||||
Genes_detected: {
|
||||
min: 444,
|
||||
max: 555
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
const createContinuousRanges = (cells) => {
|
||||
const ranges = {};
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
export default createContinuousRanges;
|
||||
@@ -0,0 +1,314 @@
|
||||
import styles from './parallelCoordinates.css';
|
||||
import {
|
||||
margin,
|
||||
width,
|
||||
height,
|
||||
innerHeight,
|
||||
color,
|
||||
dimensions,
|
||||
types,
|
||||
xscale,
|
||||
yAxis,
|
||||
} from "./util";
|
||||
|
||||
/*****************************************
|
||||
******************************************
|
||||
Canvas Parallel coordinates with svg brushing via /* via https://bl.ocks.org/syntagmatic/05a5b0897a48890133beb59c815bd953
|
||||
******************************************
|
||||
******************************************/
|
||||
|
||||
/*****************************************
|
||||
******************************************
|
||||
Render Queue via http://bl.ocks.org/syntagmatic/raw/3341641/render-queue.js
|
||||
******************************************
|
||||
******************************************/
|
||||
|
||||
const renderQueue = (function(callback1234) {
|
||||
var _queue = [], // data to be rendered
|
||||
_rate = 1000, // number of calls per frame
|
||||
_invalidate = function() {}, // invalidate last render queue
|
||||
_clear = function() {}; // clearing function
|
||||
|
||||
var rq = function(data) {
|
||||
if (data) rq.data(data);
|
||||
_invalidate();
|
||||
_clear();
|
||||
rq.render();
|
||||
};
|
||||
|
||||
rq.render = function() {
|
||||
var valid = true;
|
||||
_invalidate = rq.invalidate = function() {
|
||||
valid = false;
|
||||
};
|
||||
|
||||
function doFrame() {
|
||||
if (!valid) return true;
|
||||
var chunk = _queue.splice(0,_rate);
|
||||
chunk.map(callback1234);
|
||||
timer_frame(doFrame);
|
||||
}
|
||||
|
||||
doFrame();
|
||||
};
|
||||
|
||||
rq.data = function(data) {
|
||||
_invalidate();
|
||||
_queue = data.slice(0); // creates a copy of the data
|
||||
return rq;
|
||||
};
|
||||
|
||||
rq.add = function(data) {
|
||||
_queue = _queue.concat(data);
|
||||
};
|
||||
|
||||
rq.rate = function(value) {
|
||||
if (!arguments.length) return _rate;
|
||||
_rate = value;
|
||||
return rq;
|
||||
};
|
||||
|
||||
rq.remaining = function() {
|
||||
return _queue.length;
|
||||
};
|
||||
|
||||
// clear the canvas
|
||||
rq.clear = function(func) {
|
||||
if (!arguments.length) {
|
||||
_clear();
|
||||
return rq;
|
||||
}
|
||||
_clear = func;
|
||||
return rq;
|
||||
};
|
||||
|
||||
rq.invalidate = _invalidate;
|
||||
|
||||
var timer_frame = window.requestAnimationFrame
|
||||
|| window.webkitRequestAnimationFrame
|
||||
|| window.mozRequestAnimationFrame
|
||||
|| window.oRequestAnimationFrame
|
||||
|| window.msRequestAnimationFrame
|
||||
|| function(callback) { setTimeout(callback, 17); };
|
||||
|
||||
return rq;
|
||||
});
|
||||
|
||||
/*****************************************
|
||||
******************************************
|
||||
MAIN: drawParallelCoordinates
|
||||
******************************************
|
||||
******************************************/
|
||||
|
||||
const drawParallelCoordinates = (data) => {
|
||||
|
||||
const d3_functor = (v) => {
|
||||
return typeof v === "function" ? v : function() { return v; };
|
||||
};
|
||||
|
||||
/*****************************************
|
||||
******************************************
|
||||
Setup SVG & Canvas elements
|
||||
******************************************
|
||||
******************************************/
|
||||
|
||||
var container = d3.select("body").append("div")
|
||||
.attr("class", styles.parcoords)
|
||||
.style("width", width + margin.left + margin.right + "px")
|
||||
.style("height", height + margin.top + margin.bottom + "px");
|
||||
|
||||
var svg = container.append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||
|
||||
var canvas = container.append("canvas")
|
||||
.attr("width", width * devicePixelRatio)
|
||||
.attr("height", height * devicePixelRatio)
|
||||
.style("width", width + "px")
|
||||
.style("height", height + "px")
|
||||
.style("margin-top", margin.top + "px")
|
||||
.style("margin-left", margin.left + "px");
|
||||
|
||||
var ctx = canvas.node().getContext("2d");
|
||||
ctx.globalCompositeOperation = 'darken';
|
||||
ctx.globalAlpha = 0.15;
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.scale(devicePixelRatio, devicePixelRatio);
|
||||
|
||||
var output = d3.select("body").append("pre");
|
||||
|
||||
var axes = svg.selectAll(".axis")
|
||||
.data(dimensions)
|
||||
.enter().append("g")
|
||||
.attr("class", styles.axis)
|
||||
.attr("transform", function(d,i) { return "translate(" + xscale(i) + ")"; });
|
||||
|
||||
/*****************************************
|
||||
******************************************
|
||||
Setup SVG & Canvas elements
|
||||
******************************************
|
||||
******************************************/
|
||||
|
||||
d3.csv("https://gist.githubusercontent.com/syntagmatic/05a5b0897a48890133beb59c815bd953/raw/310a68d713eb4d351f809b6cfbcffe3d9d96a205/nutrient.csv", (error, data) => {
|
||||
if (error) throw error;
|
||||
|
||||
// shuffle the data!
|
||||
data = d3.shuffle(data);
|
||||
|
||||
data.forEach(function(d) {
|
||||
dimensions.forEach(function(p) {
|
||||
d[p.key] = !d[p.key] ? null : p.type.coerce(d[p.key]);
|
||||
});
|
||||
|
||||
// truncate long text strings to fit in data table
|
||||
for (var key in d) {
|
||||
if (d[key] && d[key].length > 35) d[key] = d[key].slice(0,36);
|
||||
}
|
||||
});
|
||||
|
||||
// type/dimension default setting happens here
|
||||
dimensions.forEach(function(dim) {
|
||||
if (!("domain" in dim)) {
|
||||
// detect domain using dimension type's extent function
|
||||
dim.domain = d3_functor(dim.type.extent)(data.map(function(d) { return d[dim.key]; }));
|
||||
}
|
||||
if (!("scale" in dim)) {
|
||||
// use type's default scale for dimension
|
||||
dim.scale = dim.type.defaultScale.copy();
|
||||
}
|
||||
dim.scale.domain(dim.domain);
|
||||
});
|
||||
|
||||
const draw = (d) => {
|
||||
ctx.strokeStyle = "rgba(0,0,0,.4)" /* color(d.food_group); */
|
||||
ctx.beginPath();
|
||||
var coords = project(d);
|
||||
coords.forEach((p,i) => {
|
||||
// this tricky bit avoids rendering null values as 0
|
||||
if (p === null) {
|
||||
// this bit renders horizontal lines on the previous/next
|
||||
// dimensions, so that sandwiched null values are visible
|
||||
if (i > 0) {
|
||||
var prev = coords[i-1];
|
||||
if (prev !== null) {
|
||||
ctx.moveTo(prev[0],prev[1]);
|
||||
ctx.lineTo(prev[0]+6,prev[1]);
|
||||
}
|
||||
}
|
||||
if (i < coords.length-1) {
|
||||
var next = coords[i+1];
|
||||
if (next !== null) {
|
||||
ctx.moveTo(next[0]-6,next[1]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
ctx.moveTo(p[0],p[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.lineTo(p[0],p[1]);
|
||||
});
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
******************************************
|
||||
Handles a brush event, toggling the display of foreground lines.
|
||||
******************************************
|
||||
******************************************/
|
||||
|
||||
const brush = () => {
|
||||
render.invalidate();
|
||||
|
||||
var actives = [];
|
||||
svg.selectAll(".axis .brush")
|
||||
.filter((d) => {
|
||||
return d3.brushSelection(this);
|
||||
})
|
||||
.each(function(d) {
|
||||
actives.push({
|
||||
dimension: d,
|
||||
extent: d3.brushSelection(this)
|
||||
});
|
||||
});
|
||||
|
||||
var selected = data.filter(function(d) {
|
||||
if (actives.every(function(active) {
|
||||
var dim = active.dimension;
|
||||
// test if point is within extents for each active brush
|
||||
return dim.type.within(d[dim.key], active.extent, dim);
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
ctx.clearRect(0,0,width,height);
|
||||
ctx.globalAlpha = d3.min([0.85/Math.pow(selected.length,0.3),1]);
|
||||
render(selected);
|
||||
|
||||
output.text(d3.tsvFormat(selected.slice(0,24)));
|
||||
console.log('fires brush', actives)
|
||||
}
|
||||
|
||||
function brushstart() {
|
||||
d3.event.sourceEvent.stopPropagation();
|
||||
}
|
||||
|
||||
var render = renderQueue(draw).rate(50);
|
||||
|
||||
ctx.clearRect(0,0,width,height);
|
||||
ctx.globalAlpha = d3.min([0.85/Math.pow(data.length,0.3),1]);
|
||||
|
||||
render(data);
|
||||
|
||||
axes.append("g")
|
||||
.each(function(d) {
|
||||
var renderAxis = "axis" in d
|
||||
? d.axis.scale(d.scale) // custom axis
|
||||
: yAxis.scale(d.scale); // default axis
|
||||
d3.select(this).call(renderAxis);
|
||||
})
|
||||
.append("text")
|
||||
.attr("class", styles.title)
|
||||
.attr("text-anchor", "start")
|
||||
.text(function(d) { return "description" in d ? d.description : d.key; });
|
||||
|
||||
// Add and store a brush for each axis.
|
||||
axes.append("g")
|
||||
.attr("class", styles.brush)
|
||||
.each(function(d) {
|
||||
d3.select(this).call(d.brush = d3.brushY()
|
||||
.extent([[-10,0], [10,height]])
|
||||
.on("start", brushstart)
|
||||
.on("brush", brush)
|
||||
.on("end", brush)
|
||||
)
|
||||
})
|
||||
.selectAll("rect")
|
||||
.attr("x", -8)
|
||||
.attr("width", 16);
|
||||
|
||||
output.text(d3.tsvFormat(data.slice(0,24)));
|
||||
|
||||
function project(d) {
|
||||
return dimensions.map(function(p,i) {
|
||||
// check if data element has property and contains a value
|
||||
if (
|
||||
!(p.key in d) ||
|
||||
d[p.key] === null
|
||||
) return null;
|
||||
|
||||
return [xscale(i),p.scale(d[p.key])];
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export default drawParallelCoordinates;
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
|
||||
This code can be found: https://bl.ocks.org/syntagmatic/05a5b0897a48890133beb59c815bd953
|
||||
|
||||
body {
|
||||
min-width: 760px;
|
||||
}
|
||||
*/
|
||||
|
||||
.parcoords {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.parcoords svg,
|
||||
.parcoords canvas {
|
||||
font: 10px sans-serif;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.parcoords canvas {
|
||||
opacity: 0.9;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.axis .title {
|
||||
font-size: 10px;
|
||||
transform: rotate(-21deg) translate(-5px,-6px);
|
||||
fill: #222;
|
||||
}
|
||||
|
||||
.axis line,
|
||||
.axis path {
|
||||
fill: none;
|
||||
stroke: #ccc;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.axis .tick text {
|
||||
fill: #222;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/*
|
||||
old, from reference bl.ocks
|
||||
.axis.manufac_name .tick text,
|
||||
.axis.food_group .tick text {
|
||||
opacity: 1;
|
||||
}
|
||||
*/
|
||||
|
||||
.axis:hover line,
|
||||
.axis:hover path,
|
||||
.axis.active line,
|
||||
.axis.active path {
|
||||
fill: none;
|
||||
stroke: #222;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.axis:hover .title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.axis:hover .tick text {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.axis.active .title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.axis.active .tick text {
|
||||
opacity: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.brush .extent {
|
||||
fill-opacity: .3;
|
||||
stroke: #fff;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
pre {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
margin: 6px 12px;
|
||||
tab-size: 40;
|
||||
font-size: 10px;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
export const margin = {top: 66, right: 110, bottom: 20, left: 188};
|
||||
export const width = document.body.clientWidth - margin.left - margin.right;
|
||||
export const height = 340 - margin.top - margin.bottom;
|
||||
export const innerHeight = height - 2;
|
||||
|
||||
export const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
|
||||
export const color = d3.scaleOrdinal()
|
||||
.range(["#5DA5B3","#D58323","#DD6CA7","#54AF52","#8C92E8","#E15E5A","#725D82","#776327","#50AB84","#954D56","#AB9C27","#517C3F","#9D5130","#357468","#5E9ACF","#C47DCB","#7D9E33","#DB7F85","#BA89AD","#4C6C86","#B59248","#D8597D","#944F7E","#D67D4B","#8F86C2"]);
|
||||
|
||||
export const types = {
|
||||
"Number": {
|
||||
key: "Number",
|
||||
coerce: function(d) { return +d; },
|
||||
extent: d3.extent,
|
||||
within: function(d, extent, dim) { return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]; },
|
||||
defaultScale: d3.scaleLinear().range([innerHeight, 0])
|
||||
},
|
||||
"String": {
|
||||
key: "String",
|
||||
coerce: String,
|
||||
extent: function (data) { return data.sort(); },
|
||||
within: function(d, extent, dim) { return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]; },
|
||||
defaultScale: d3.scalePoint().range([0, innerHeight])
|
||||
},
|
||||
"Date": {
|
||||
key: "Date",
|
||||
coerce: function(d) { return new Date(d); },
|
||||
extent: d3.extent,
|
||||
within: function(d, extent, dim) { return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]; },
|
||||
defaultScale: d3.scaleTime().range([0, innerHeight])
|
||||
}
|
||||
};
|
||||
|
||||
export const dimensions = [
|
||||
{
|
||||
key: "Total lipid (fat) (g)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Sugars, total (g)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Calcium, Ca (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Sodium, Na (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Phosphorus, P (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Potassium, K (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Thiamin (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Riboflavin (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Niacin (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Iron, Fe (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Magnesium, Mg (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Protein (g)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Zinc, Zn (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Vitamin B-6 (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Vitamin B-12 (mcg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Folic acid (mcg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Selenium, Se (mcg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Vitamin A, IU (IU)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Vitamin K (phylloquinone) (mcg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Vitamin C, total ascorbic acid (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Vitamin D (IU)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Cholesterol (mg)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Fiber, total dietary (g)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
},
|
||||
{
|
||||
key: "Carbohydrate, by difference (g)",
|
||||
type: types["Number"],
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0])
|
||||
}
|
||||
];
|
||||
|
||||
export const xscale = d3.scalePoint()
|
||||
.domain(d3.range(dimensions.length))
|
||||
.range([0, width]);
|
||||
|
||||
export const yAxis = d3.axisLeft();
|
||||
@@ -0,0 +1,3 @@
|
||||
.header {
|
||||
background: red;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
|
||||
import Container from './container';
|
||||
import styles from './header.css';
|
||||
|
||||
|
||||
const Header = () => (
|
||||
<header className={styles.header}>
|
||||
<Container>
|
||||
|
||||
</Container>
|
||||
</header>
|
||||
);
|
||||
|
||||
export default Header;
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import _ from "lodash";
|
||||
import Helmet from 'react-helmet';
|
||||
import Container from './container';
|
||||
|
||||
import Categorical from "./categorical/categorical";
|
||||
import Continuous from "./continuous/continuous";
|
||||
|
||||
const Home = () => {
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Helmet title="cellxgene" />
|
||||
<h1><Link to="/page2">cellxgene</Link></h1>
|
||||
<Categorical/>
|
||||
<Continuous/>
|
||||
</Container>
|
||||
)
|
||||
};
|
||||
|
||||
export default Home;
|
||||
|
||||
// <Categorical title={"Sample type"} category={types}/>
|
||||
// <Categorical title={"Selection"} category={selection}/>
|
||||
// <Categorical title={"Location"} category={location}/>
|
||||
// <Categorical title={"Sample name"} category={names}/>
|
||||
@@ -0,0 +1,33 @@
|
||||
.heroContainer {
|
||||
width: 100%;
|
||||
height: 95vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero {
|
||||
font-size: 48;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.subHero {
|
||||
font-size: 18;
|
||||
max-width: 600;
|
||||
text-align: "center";
|
||||
}
|
||||
|
||||
.primaryButton {
|
||||
border: 1px solid black;
|
||||
padding: 10px 15px;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.or {
|
||||
margin: 20px;
|
||||
font-family: Georgia;
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Helmet from 'react-helmet';
|
||||
import styles from './page2.css';
|
||||
|
||||
import Container from './container';
|
||||
|
||||
const Page2 = () => (
|
||||
<Container>
|
||||
<Helmet title="cellxgene" />
|
||||
<div className={styles.heroContainer}>
|
||||
<h1 className={styles.hero}>cellxgene</h1>
|
||||
<p className={styles.subHero}>
|
||||
A data exploration interface for single cell genetic expression matrices. Subset, filter, cluster & validate, all in one place.
|
||||
</p>
|
||||
<div>
|
||||
<Link to="/"><button className={styles.primaryButton}>explore a sample dataset</button></Link>
|
||||
<span className={styles.or}>or</span>
|
||||
<button className={styles.primaryButton}>get started with your own data</button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
|
||||
export default Page2;
|
||||
Reference in New Issue
Block a user