Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b0b8ed5
Renamed incorrect png file, commenting out text_annotation import.
drew-diamantoukos Aug 17, 2018
50b1c18
Nuking 1_5. Adding main.js module and going from there.
drew-diamantoukos Aug 17, 2018
c362b7b
Replacing all instances of var with let. Starting the fight against c…
drew-diamantoukos Aug 17, 2018
911d345
Added tsconfig and tslint file
drew-diamantoukos Aug 18, 2018
2b33171
Added a types file to allow d3/pixi types to show up for type checking
drew-diamantoukos Aug 18, 2018
170a863
Major breakthrough with requirejs and vendor code
drew-diamantoukos Aug 18, 2018
de28456
Added pixijs to vendor code. Working on exporting variables.
drew-diamantoukos Aug 19, 2018
652a077
Exporting more functions
drew-diamantoukos Aug 20, 2018
7f722bd
Spring - now with color!
drew-diamantoukos Aug 20, 2018
fb9e7d7
Zooming in fixes
drew-diamantoukos Aug 20, 2018
79e2e36
Working on getting data all async-like
drew-diamantoukos Aug 21, 2018
2da09f3
Lines!
drew-diamantoukos Aug 21, 2018
0ca4930
Exporting module instances from main.
drew-diamantoukos Aug 22, 2018
c4286ef
One Step Closer
drew-diamantoukos Aug 22, 2018
c5bfd64
Updating d3 select commands, part 1
drew-diamantoukos Aug 22, 2018
c4d5b9f
Adjusting callbacks to use lambda expressions to better capture this …
drew-diamantoukos Aug 22, 2018
e0cd1cc
Updated smoothingimputation, selectionlogic and doublet to be singletons
drew-diamantoukos Aug 23, 2018
94d0e83
Updated selection code to use d3-v5 API
drew-diamantoukos Aug 23, 2018
2110e69
Added JSDoc annotation for instance fields
drew-diamantoukos Aug 23, 2018
87b7874
Split up vendor and non-vendor code. Changed scripts_1_6_dev folder n…
drew-diamantoukos Aug 23, 2018
2689f98
Renamed springViewer_1_6_dev.html to springViewer.html
drew-diamantoukos Aug 23, 2018
3e63dee
Cleaning up more JS errors, added some maintenance hooks for linting.
drew-diamantoukos Aug 23, 2018
9ff5786
Resolved a selection bug where the box wasn't going away
drew-diamantoukos Aug 23, 2018
1071db3
File helper, getting coordinate data from chell if available
drew-diamantoukos Aug 27, 2018
15c92c9
Add parenthesis to python code, converted bulk of anonymous functions…
drew-diamantoukos Aug 29, 2018
a210393
Added code to handle sending selected points via PostMessage API
drew-diamantoukos Nov 6, 2018
e699d99
Added a 'init' event to set the initial cells/category. Renamed 'call…
drew-diamantoukos Nov 14, 2018
53041a7
Added fallback for gene colors
drew-diamantoukos Nov 20, 2018
eecf744
Added dist
drew-diamantoukos Nov 20, 2018
88d2a55
Added datasets
drew-diamantoukos Nov 20, 2018
adfc71d
Allowing trusted messages from same origin. Using local type definiti…
drew-diamantoukos Nov 21, 2018
ed2d812
Removed debug logging
drew-diamantoukos Nov 21, 2018
b788c11
tabula muris dataset
drew-diamantoukos Nov 26, 2018
9be5ea8
Removing datasets from repo
drew-diamantoukos Nov 30, 2018
b9ebf57
Added finally block to update count labels when reading event.
drew-diamantoukos Nov 30, 2018
9799d10
Turned on visibility for clone sprite containers
drew-diamantoukos Dec 2, 2018
ad14191
Setting initial zoom correctly now
drew-diamantoukos Dec 2, 2018
914c537
Touched up file_helper to properly catch and retry file fetch
drew-diamantoukos Dec 2, 2018
8c06d65
Fixed categorical color track loading; updated start server code to
swolock Dec 3, 2018
a249ed5
I forgot messages come in as strings not objects
drew-diamantoukos Dec 3, 2018
7e9da8f
Merge remote-tracking branch 'upstream/pr/spring-of-rebirth' into spr…
drew-diamantoukos Dec 3, 2018
519b316
Getting label key in main.js
drew-diamantoukos Dec 3, 2018
a5a43ee
Created function to streamline passing indices to parent, only sendin…
drew-diamantoukos Dec 5, 2018
9836a86
Updated PR to match latest changes to doublet_detector, colorBar and …
drew-diamantoukos Mar 8, 2019
ed54819
Remoed scripts_1_6 and built lib
drew-diamantoukos Mar 8, 2019
cceb653
Adding requirejs as explicit dependency
drew-diamantoukos Mar 22, 2019
6d6b898
Python3 fixes
drew-diamantoukos Apr 10, 2019
e589884
Added script timeout for main.js
drew-diamantoukos Oct 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules

datasets/**/*.npz
*.hdf5

yarn-error.log
.DS_STORE

.pyc
9 changes: 9 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"bracketSpacing": true,
"printWidth": 120,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": false
}
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"cSpell.words": [
"ncells",
"numpy",
"scipy",
"sklearn"
]
}
101 changes: 74 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
### Installing Python libraries

To run SPRING Viewer locally, make sure Python 2.7 is installed (and that it's your active version). You will also need the following Python libraries:

`scikit-learn`
`numpy`
`scipy`
`matplotlib`
`h5py`
`networkx`
`fa2`
`python-louvain`
# SPRING

We recommend Anaconda to manage your Python libraries. You can download it here (be sure to get the Python 2.7 version): https://conda.io/miniconda.html. Libraries can then be installed using the command `conda`. To do so, open Terminal (Mac) or Anaconda Prompt (Windows) and enter:
<!-- TOC -->

`conda install scikit-learn numpy scipy matplotlib h5py`
- [SPRING](#spring)
- [Setting Up A SPRING Data Directory](#setting-up-a-spring-data-directory)
- [Backend](#backend)
- [Installing Python libraries](#installing-python-libraries)
- [Frontend](#frontend)
- [Development Build](#development-build)
- [Production Build](#production-build)
- [RequireJS](#requirejs)
- [Running SPRING Viewer](#running-spring-viewer)

The remaining libraries can be installed using `pip`. Note that if you're a Windows user, you'll first need to install Microsoft Visual C++ compiler for Python (available from http://aka.ms/vcpython27). Enter the following into Terminal or Anaconda Prompt:
<!-- /TOC -->

`pip install networkx fa2 python-louvain`
[SPRING](https://doi.org/10.1093/bioinformatics/btx792) is a collection of pre-processing scripts and a web browser-based tool for visualizing and interacting with high dimensional data.

## Setting Up A SPRING Data Directory

### Setting up a SPRING data directory
See the example notebooks:
[Hematopoietic progenitor FACS subpopulations](./data_prep/spring_example_HPCs.ipynb)
[Mature blood cells (10X Genomics 4k PBMCs)](./data_prep/spring_example_pbmc4k.ipynb)
[Mature blood cells (10X Genomics 4k PBMCs)](./data_prep/spring_example_pbmc4k.ipynb)

A SPRING data set consist of a main directory and any number of subdirectories, with each subdirectory corresponding to one SPRING plot (i.e. subplot) that draws on a data matrix stored in the main directory. The main directory should have the following files, as well as one subdirectory for each SPRING plot.
A SPRING data set consist of a main directory and any number of subdirectories, with each subdirectory corresponding to one SPRING plot (i.e. subplot) that draws on a data matrix stored in the main directory. The main directory should have the following files, as well as one subdirectory for each SPRING plot.

`counts_norm.npz`
`counts_norm_sparse_cells.hdf5`
`counts_norm_sparse_genes.hdf5`
`genes.txt`
`genes.txt`

Each subdirectory should contain:
Each subdirectory should contain:

`categorical_coloring_data.json`
`cell_filter.npy`
Expand All @@ -42,15 +39,65 @@ Each subdirectory should contain:
`coordinates.txt`
`edges.csv`
`graph_data.json`
`run_info.json`
`run_info.json`

Place the main directory somewhere inside folder that contains this README and the other SPRING file. We recommend that you create a special `datasets` directory. For example, if you have a main data set called `human_bone_marrow` and another called `frog_embryo`, you could place them in `./datasets/human_bone_marrow/` and `./datasets/frog_embryo/`.

## Backend

### Installing Python libraries

To run SPRING Viewer locally, make sure Python 2.7 is installed (and that it's your active version). You will also need the following Python libraries:

`scikit-learn`
`numpy`
`scipy`
`h5py`
`networkx`
`fa2`
`python-louvain`

We recommend Anaconda to manage your Python libraries. You can download it here (be sure to get the Python 2.7 version): https://conda.io/miniconda.html. Libraries can then be installed using the command `conda`. To do so, open Terminal (Mac) or Anaconda Prompt (Windows) and enter:

`conda install scikit-learn numpy scipy h5py`

The remaining libraries can be installed using `pip`. Note that if you're a Windows user, you'll first need to install Microsoft Visual C++ compiler for Python (available from http://aka.ms/vcpython27). Enter the following into Terminal or Anaconda Prompt:

`pip install networkx fa2 python-louvain`

## Frontend

Place the main directory somehwere inside folder that contains this README and the other SPRING file. We recommend that you create a special `datasets` directory. For example, if you have a main data set called `human_bone_marrow` and another called `frog_embryo`, you could place them in `./datasets/human_bone_marrow/` and `./datasets/frog_embryo/`.
The SPRING frontend is setup as a JavaScript module using [Yarn](https://yarnpkg.com/en/) as a package manager and [TypeScript](https://www.typescriptlang.org/) as a transpiler - Meaning we can write code that uses features like [async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) while still supporting older browsers!

### Development Build

### Running SPRING Viewer
To get the frontend building for development purpose, open your favorite terminal/shell into this directory and then run:

1. Open Terminal (Mac) or Anaconda Prompt (Windows) and change directories (`cd`) to the directory containing this README file (`SPRING_dev/`).
```sh
yarn
yarn build --watch
```

This will compile code inside `src/` and put it inside `dist/` as well as watch for file changes and re-compile as needed. Neat!

### Production Build

Similar to the above, run the following two commands to create the production build:

```sh
yarn
yarn build
```

### RequireJS

Further, please note there is only a single entry point for the app on the springViewer.html page - namely, `app.js`. Digging down a bit, you'll see that it is setup as a [RequireJS](https://requirejs.org/) module and is **pulling code from the vendor and dist directories**!

This setup seems to provide the most flexibility in allowing spring to come bundled with minified 3rd party library code (d3, jquery, pixi.js, etc), while still allowing the app code to be setup in a modular way and not adding in a lot of extra configuration using tools like Rollup or Webpack.

## Running SPRING Viewer

1. Open Terminal (Mac) or Anaconda Prompt (Windows) and change directories (`cd`) to the directory containing this README file (`SPRING_dev/`).
2. Start a local server by entering the following: `python -m CGIHTTPServer 8000`
3. Open web browser (preferably Chrome; best to use incognito mode to ensure no cached data is used).
4. View data set by navigating to corresponding URL: http://localhost:8000/springViewer_1_6_dev.html?path_to/main/subplot. In the example above, if you wanted to view a SPRING plot called `HSC` in the main directory `human_bone_marrow`, then you would navigate to http://localhost:8000/springViewer_1_6_dev.html?datasets/human_bone_marrow/HSC

4. View data set by navigating to corresponding URL: http://localhost:8000/springViewer.html?path_to/main/subplot. In the example above, if you wanted to view a SPRING plot called `HSC` in the main directory `human_bone_marrow`, then you would navigate to http://localhost:8000/springViewer.html?datasets/human_bone_marrow/HSC
57 changes: 57 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
requirejs.config({
baseUrl: 'vendor',
shim: {
PIXI: { exports: 'PIXI' },
},
paths: {
dist: '../dist',
d3: 'd3.v5.min',
html2canvas: 'html2canvas.min',
spinner: 'spin.min',
sweetalert: 'sweetalert.min',
},
});

if (!window.cacheData) {
window.cacheData = new Map();
}

window.addEventListener('message', event => {
if (!event.isTrusted && event.origin === window.location.origin) {
return;
}
try {
if (typeof event.data === 'string') {
const parsedData = JSON.parse(event.data);
switch (parsedData.type) {
case 'init': {
if (parsedData.payload.indices) {
window.cacheData.set('indices', parsedData.payload.indices);
}

if (parsedData.payload.categories) {
window.cacheData.set('categories', parsedData.payload.categories);
}
}
case 'selected-cells-update': {
if (parsedData.payload.coordinates) {
window.cacheData.set('selected-cells', parsedData.payload.coordinates);
}
}
default: {
break;
}
}
}
} catch (err) {
console.log(`Unable to parse received message.\n\
Data: ${event.data}
Error: ${err}`);
}
});

requirejs.config({
waitSeconds: 200,
});

requirejs(['dist/main']);
83 changes: 43 additions & 40 deletions cgi-bin/apply_gene_set_retrospective.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env python
#========================================================================================#
import numpy as np, sys, h5py, json
import numpy as np
import sys
import h5py
import json

base_dir = sys.argv[1]
sub_dirs = sys.argv[2]
Expand All @@ -9,58 +12,58 @@
hf = h5py.File(base_dir + '/counts_norm_sparse_genes.hdf5', 'r')
ncells = hf.attrs['ncells']
valid_genes = hf.get('counts').keys()
gene_map = {g.split()[0]:g for g in valid_genes}
gene_map = {g.split()[0]: g for g in valid_genes}


# Load gene sets
gene_sets = {}
all_genes = set([])
for l in open(gene_sets_path).read().replace('\r','\n').split('\n'):
l = l.split('\t')
if len(l) > 1:
gene = l[0]
name = l[1]
if gene in gene_map: gene = gene_map[gene]
if not gene in valid_genes: print 'Invalid',gene
else:
if not name in gene_sets:
gene_sets[name] = []
gene_sets[name].append(gene)
all_genes.add(gene)
for l in open(gene_sets_path).read().replace('\r', '\n').split('\n'):
split_l = l.split('\t')
if len(l) > 1:
gene = split_l[0]
name = split_l[1]
if gene in gene_map:
gene = gene_map[gene]
if gene not in valid_genes:
print('Invalid', gene)
else:
if name not in gene_sets:
gene_sets[name] = []
gene_sets[name].append(gene)
all_genes.add(gene)


# Load gene expression
# Load gene expression
gene_exp = {}
for g in all_genes:
ee = np.zeros(ncells)
counts = np.array(hf.get('counts').get(g))
cell_ix = np.array(hf.get('cell_ix').get(g))
ee[cell_ix] = counts
gene_exp[g] = ee
ee = np.zeros(ncells)
counts = np.array(hf.get('counts').get(g))
cell_ix = np.array(hf.get('cell_ix').get(g))
ee[cell_ix] = counts
gene_exp[g] = ee

# compute scores
scores = {}
for k,gs in gene_sets.items():
Z = np.array([gene_exp[g] for g in gs])
Z = (Z - np.mean(Z,axis=1)[:,None]) / (np.std(Z,axis=1)[:,None] + .0001)
ss = np.sum(Z,axis=0)
ss = ss - np.min(ss)
scores[k] = ss
for k, gs in gene_sets.items():
Z = np.array([gene_exp[g] for g in gs])
Z = (Z - np.mean(Z, axis=1)[:, None]) / \
(np.std(Z, axis=1)[:, None] + .0001)
ss = np.sum(Z, axis=0)
ss = ss - np.min(ss)
scores[k] = ss

# Apply to each subplots
for dd in sub_dirs.split(','):
cell_ix = np.load(base_dir+'/'+dd+'/cell_filter.npy')
f = open(base_dir+'/'+dd+'/color_data_gene_sets.csv','a')
for k,ss in scores.items():
newline = ','.join([k]+[repr(x) for x in ss[cell_ix]])
f.write(newline+'\n')
f.close()

color_stats = json.load(open(base_dir+'/'+dd+'/color_stats.json'))
for k,ss in scores.items():
color_stats[k] = (np.mean(ss),np.std(ss),np.min(ss),np.max(ss),np.percentile(ss,99))
json.dump(color_stats,open(base_dir+'/'+dd+'/color_stats.json','w'))



cell_ix = np.load(base_dir + '/' + dd + '/cell_filter.npy')
f = open(base_dir + '/' + dd + '/color_data_gene_sets.csv', 'a')
for k, ss in scores.items():
newline = ','.join([k] + [repr(x) for x in ss[cell_ix]])
f.write(newline + '\n')
f.close()

color_stats = json.load(open(base_dir + '/' + dd + '/color_stats.json'))
for k, ss in scores.items():
color_stats[k] = (np.mean(ss), np.std(ss), np.min(ss),
np.max(ss), np.percentile(ss, 99))
json.dump(color_stats, open(base_dir + '/' + dd + '/color_stats.json', 'w'))
Loading