scRNA-seq_analysis

This commit is contained in:
veghp 2019-07-08 12:22:01 +01:00
commit 82cc2d191e
188 changed files with 146184 additions and 0 deletions

33694
pipelines/90_web_portal/genes.tsv Executable file

File diff suppressed because it is too large Load diff

42653
pipelines/90_web_portal/hgnc.csv Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
file_name: ../../data/dummydata.RDS
output_folder: ../../output/dummydata_web_portal
dr_coordonates: UMAP->umap; tSNE->tsne; FDG->fdg;
Cell Labels->Annotation_5->null;

View file

@ -0,0 +1,4 @@
file_name: ../../data/liver_all.RDS
output_folder: ../../output/liver_web_portal
dr_coordonates: UMAP->umap; tSNE->tsne; FDG->fdg;
Cell Labels->cell.labels->../../resources/liver_cell_type_colours.csv;Cell Subsets->cell.labels->null;Flow gate->sort.ids->null;Sample->sample.ids->null;Gender->gender->null;

View file

@ -0,0 +1,4 @@
file_name: ../../data/thymus.h5ad
output_folder: ../../output/thymus_web_portal
dr_coordonates: UMAP->X_umap; tSNE->X_tsne; FDG->X_draw_graph_fa;
Cell Labels->Annotation->null;Flow gate->sort->null;Sample->sample->null;Gender->gender->null;

View file

@ -0,0 +1,94 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Dec 20 12:00:47 2018
@author: doru
"""
# gene expression should be at data.X
# gene symbols should be at data.var.GeneName
# DRs should be at data.obsm
# categoeis should be columns at data.obs
import sys
option_files = sys.argv[1]
#option_files = "thymus_web_portal_options.txt"
import matplotlib; matplotlib.use('Agg');
import scanpy.api as sc
from os.path import join
from scipy.io import mmwrite
from scipy.sparse import hstack
import numpy as np
import random
import pandas as pd
# extract options
options_fobj = open(option_files, 'r')
options = options_fobj.readlines()
options_fobj.close()
options = [op.strip() for op in options]
# make file_name variable
file_name = options[0].split(':')[1].strip()
# make output_folder variable
output_folder = options[1].split(':')[1].strip()
# make dr_coordinates
dr_coordinates = options[2].split(':')[1].strip()
dr_coordinates = dr_coordinates.split(";")
dr_coordinates = [dr.split('->')[1] for dr in dr_coordinates if dr != '']
# extract categories
categories = options[3].split(';')
categories = [cat.split('->') for cat in categories if cat != '']
data = sc.read(file_name)
# save expression data
expression_data_filename = join(output_folder, 'expression')
nUMI = np.array(data.obs.n_UMIs)
nUMI = nUMI.reshape((nUMI.shape[0], 1))
nGene = np.array(data.obs.n_genes)
nGene = nUMI.reshape((nGene.shape[0], 1))
gene_expression = hstack([data.X, nUMI, nGene])
mmwrite(expression_data_filename, gene_expression)
# save gene names
gene_names = [g for g in data.var.GeneName]
gene_names.append('nUMI')
gene_names.append('nGene')
gene_names = '\n'.join(gene_names)
gene_names_fobj = open(join(output_folder, 'gene_names.txt'), 'w')
gene_names_fobj.write(gene_names)
gene_names_fobj.close()
# get DR coordinates
for index, dr_coor in enumerate(dr_coordinates):
if index == 0:
dr_data = data.obsm[dr_coor]
else:
dr_data = np.concatenate([dr_data, data.obsm[dr_coor]], axis = 1)
np.savetxt(join(output_folder, "dr.csv"), dr_data, delimiter=",")
# get categories
for index, category in enumerate(categories):
slot = category[1]
category_col = category[2]
category_data = data.obs[slot]
if category_col == 'null':
category_unique = category_data.values.categories
r = lambda: random.randint(0,255)
category_col = {}
for unique in category_unique:
category_col[unique] = '#%02X%02X%02X' % (r(),r(),r())
category_col = category_data.map(category_col)
else:
category_col = pd.read.csv('when colour keys are ready continue script here')
categories_data = pd.concat([category_data, category_col], axis = 1)
categories_data.columns = [category[0], '{c}_Colour'.format(c = category[0])]
if index == 0:
csv_data = categories_data
else:
csv_data = pd.concat([csv_data, categories_data], axis = 1)
categories_fname = join(output_folder, 'categories.csv')
csv_data.to_csv(categories_fname)

View file

@ -0,0 +1,37 @@
<?php
$mot_de_pass = $_GET['mot_de_pass'];
$password = "clear_to_go";
if ($mot_de_pass != $password){
exit('Password not correct');
}
$category_name = $_GET["category"];
$color_key_file = $category_name . "_color_key.csv";
$color_key_file = "./categories/" . $color_key_file;
$color_key_file = fopen($color_key_file, "r");
$line = fgets($color_key_file );
$data_string = "";
while (($line = fgets($color_key_file)) !== false){
$col_key = explode(",", $line);
$cell_name = $col_key[0];
$cell_col = $col_key[1];
$button_html = str_replace('cell_name', str_replace('"', "", $cell_name), "<div style='background-color: cell_color;'><input type = 'checkbox' onchange='toggleCategoryAction()' name = 'cellTypeBtn' id='cell_name' checked /><label for = 'cell_name'> cell_name</label></div>");
$button_html = str_replace('cell_color', str_replace('"', "", $cell_col), $button_html);
$data_string = $data_string . $button_html;
}
fclose($color_key_file);
$categories_colors_file = "./categories/" . $category_name . "_colors";
$categories_colors_file = fopen($categories_colors_file, "r");
$categories_colors = fgets($categories_colors_file);
fclose($categories_colors_file);
$data_string = $data_string . "&&" . $categories_colors;
$categories_indices_file = "./categories/" . $category_name . "_indices";
$categories_indices_file = fopen($categories_indices_file, "r");
$categories_indices = fgets($categories_indices_file);
fclose($categories_indices_file);
$data_string = $data_string . "&&" . $categories_indices;
echo $data_string;
?>

View file

@ -0,0 +1,7 @@
<?php
$dr_fname = "./dr/" . $_GET["dr_name"] . "_coordinates";
$dr_file = fopen($dr_fname, 'r');
$dr_array = fgets($dr_file);
fclose($dr_file);
echo $dr_array;
?>

View file

@ -0,0 +1,7 @@
<?php
$gene_name = $_GET["gene_name"];
$gene_expression_file = './genes/' . $gene_name;
$gene_expression_file = fopen($gene_expression_file, 'r');
$gene_expression = fgets($gene_expression_file);
echo $gene_expression;
?>

View file

@ -0,0 +1,753 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Gene expression web portal</title>
<meta name="description" content="Gene expression web portal for single cell RNA sequencing data made for the Human Cell Atlas at Newcastle University">
<meta name="author" content="Dorin-Mirel Popescu">
<style>
body {
font-family: Avenir, Arial, sans-serif;
}
#div_left {
float: left;
}
#canvasdiv {
overflow-x: scroll;
overflow-y: scroll;
max-height: 90vh;
}
#typesControlPanel {
height: 25em;
overflow-y: auto;
}
#cursorText{
position:absolute;
background-color: black;
color : white;
}
</style>
</head>
<body>
<?php
$password = 'clear_to_go';
echo "<script type = 'text/javascript'>";
echo "var password = 'clear_to_go'";
echo "</script>";
?>
<div id = "div_left">
<form>
<fieldset>
<legend><b>Visualisation options</b></legend>
<label for = 'particleSizeBar'>Particle size: </label>
<input type='range' name = 'particleSizeBar' min = .3 max = 7 step=0.1 oninput='setParticleSize(value)' value = 2 /><br/>
<label for = 'alphaInput'>Transparency: </label>
<input type='range' name = 'alphaInput' min = 0 max = 1000 oninput='setAlpha(value)' value = 1000 /><br/>
<label for = 'canvasSizeInput'>Canvas size: </label>
<input type='range' name = 'canvasSizeInput' min = 200 max = 2000 oninput='setCanvasSize(value)' value = 500 /><br/>
</fieldset>
</form>
<form>
<fieldset>
<legend><b>Cell types</b></legend>
<div>
<div>
Select category: <select id='categorySelectMenu' onchange = 'updateCategories(value)'>
<?php
$categories_file = fopen("./categories/categories_key", "r");
$categories_content = fgets($categories_file);
fclose($categories_file);
$categories = explode(";", $categories_content);
foreach($categories as $category){
$category_fields = explode("->", $category);
$category_name = $category_fields[0];
$category_value = $category_fields[1];
echo "<option value='" . $category_value . "'>" . $category_name . "</option>";
}
?>
</select>
</div>
</div>
<label for='toggleRadio'><input type='checkbox' name = 'toggleRadio' id='toggleRadio' onchange='toggleAllTypes()' checked />Show all</label>
<div id='typesControlPanel'>
</div>
</fieldset>
</form>
</div>
<div id = "div_right">
<div>
<b>Colour by:</b>
<label for='colourType_t'><input type='radio' name='colourType' id='colourType_t' onchange='setColourBy(value)' value='cell_type' checked />Cell type</label>
<label for='colourType_g'><input type='radio' name='colourType' id='colourType_g' onchange='setColourBy(value)' value='gene_expression' />Gene expression</label>
</div>
<table id = "geneSelectorTable">
<tr>
<td>
<label for='geneFamilySelector'>Gene family:</label>
</td>
<td>
<select name='geneFamilySelector' id='geneFamilySelector' onchange='selectFamily(value)'>
</select>
</td>
</tr>
<tr>
<td>
<label for='geneSymbolSelector'>Gene symbol:</label>
</td>
<td>
<input type = 'text' id='genelist_input' name = 'geneSymbolSelector_datalist' list='geneSymbolSelector_datalist' onchange='getGeneExpression(this)'>
<datalist id = 'geneSymbolSelector_datalist'>
<select onchange = 'getGeneExpression(this)' id ='geneSymbolSelector'></select>
</datalist>
</td>
</tr>
</table>
<label for = 'bgColorRadio_white'><input id = 'bgColorRadio_white' name = "bgColorRadio" type = "radio" value = 'white' onchange='setBackground(value)' checked/>White background </label>
<label for = 'bgColorRadio_dark'><input id = 'bgColorRadio_dark' name = "bgColorRadio" type = "radio" value = 'dark' onchange='setBackground(value)' />Dark background </label>
<br/><span id='expression_scale'></span>
<div>
Choose coordinates: <select onchange = 'getCoordinates(value)'>
<?php
$dr_file = fopen("./dr/dr_key", "r");
$dr_content = fgets($dr_file);
fclose($dr_file);
$dr_cats = explode(";", $dr_content);
foreach($dr_cats as $dr_cat){
echo 1;
$dr_fields = explode("->", $dr_cat);
$dr_name = $dr_fields[0];
echo "<option value='" . $dr_name . "'>" . $dr_name . "</option>";
}
?>
</select>
</div>
<div id='canvasdiv'><canvas id='canvas' width=500 height=500></canvas></div>
</div>
<script id='vertex-shader' type='x-shader/x-fragment'>
attribute vec4 a_Position;
attribute vec3 a_Color;
uniform float u_basePointSize;
uniform float u_Alpha;
uniform int u_PaintFeatureScale;
varying vec4 v_Color;
void main() {
gl_Position = a_Position;
gl_PointSize = u_basePointSize;
if (u_PaintFeatureScale == 0){
v_Color = vec4(a_Color, u_Alpha);
}
else{
float r = 0.0;
float g = 0.0;
float b = 0.0;
r = max(0.0, 2.0 * a_Color.r - 1.0);
b = max(0.0, 2.0 * (1.0 - a_Color.r) - 1.0);
g = 1.0 - 2.0 * abs(a_Color.r - 0.5);
v_Color = vec4(r, g, b, u_Alpha);
}
}
</script>
<script id ='fragment-shader' type='x-shader/x-fragment'>
precision mediump float;
varying vec4 v_Color;
void main() {
float r = 0.0;
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
r = dot(cxy, cxy);
if (r > 1.0){
discard;
}
gl_FragColor = v_Color;
}
</script>
<?php
echo "<script type = 'text/javascript'>";
$gene_families_file = fopen("./genes/gene_lists", "r");
$gene_families_content = fgets($gene_families_file);
fclose($gene_families_file);
echo $gene_families_content;
$dr_file = fopen("./dr/dr_key", "r");
$dr_content = fgets($dr_file);
fclose($dr_file);
$dr_cats = explode(";", $dr_content);
$first_dr = explode('->', $dr_cats[0])[0];
echo "first_dr = '" . $first_dr . "'";
echo "</script>";
?>
<script type = 'text/javascript'>
var Matrix4 = function(opt_src) {
var i, s, d;
if (opt_src && typeof opt_src === 'object' && opt_src.hasOwnProperty('elements')) {
s = opt_src.elements;
d = new Float32Array(16);
for (i = 0; i < 16; ++i) {
d[i] = s[i];
}
this.elements = d;
} else {
this.elements = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
}
};
Matrix4.prototype.setTranslate = function(x, y, z) {
var e = this.elements;
e[0] = 1; e[4] = 0; e[8] = 0; e[12] = x;
e[1] = 0; e[5] = 1; e[9] = 0; e[13] = y;
e[2] = 0; e[6] = 0; e[10] = 1; e[14] = z;
e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1;
return this;
};
Matrix4.prototype.setLookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
var e, fx, fy, fz, rlf, sx, sy, sz, rls, ux, uy, uz;
fx = centerX - eyeX;
fy = centerY - eyeY;
fz = centerZ - eyeZ;
// Normalize f.
rlf = 1 / Math.sqrt(fx*fx + fy*fy + fz*fz);
fx *= rlf;
fy *= rlf;
fz *= rlf;
// Calculate cross product of f and up.
sx = fy * upZ - fz * upY;
sy = fz * upX - fx * upZ;
sz = fx * upY - fy * upX;
// Normalize s.
rls = 1 / Math.sqrt(sx*sx + sy*sy + sz*sz);
sx *= rls;
sy *= rls;
sz *= rls;
// Calculate cross product of s and f.
ux = sy * fz - sz * fy;
uy = sz * fx - sx * fz;
uz = sx * fy - sy * fx;
// Set to this.
e = this.elements;
e[0] = sx;
e[1] = ux;
e[2] = -fx;
e[3] = 0;
e[4] = sy;
e[5] = uy;
e[6] = -fy;
e[7] = 0;
e[8] = sz;
e[9] = uz;
e[10] = -fz;
e[11] = 0;
e[12] = 0;
e[13] = 0;
e[14] = 0;
e[15] = 1;
// Translate.
return this.translate(-eyeX, -eyeY, -eyeZ);
};
Matrix4.prototype.translate = function(x, y, z) {
var e = this.elements;
e[12] += e[0] * x + e[4] * y + e[8] * z;
e[13] += e[1] * x + e[5] * y + e[9] * z;
e[14] += e[2] * x + e[6] * y + e[10] * z;
e[15] += e[3] * x + e[7] * y + e[11] * z;
return this;
};
Matrix4.prototype.setPerspective = function(fovy, aspect, near, far) {
var e, rd, s, ct;
if (near === far || aspect === 0) {
throw 'null frustum';
}
if (near <= 0) {
throw 'near <= 0';
}
if (far <= 0) {
throw 'far <= 0';
}
fovy = Math.PI * fovy / 180 / 2;
s = Math.sin(fovy);
if (s === 0) {
throw 'null frustum';
}
rd = 1 / (far - near);
ct = Math.cos(fovy) / s;
e = this.elements;
e[0] = ct / aspect;
e[1] = 0;
e[2] = 0;
e[3] = 0;
e[4] = 0;
e[5] = ct;
e[6] = 0;
e[7] = 0;
e[8] = 0;
e[9] = 0;
e[10] = -(far + near) * rd;
e[11] = -1;
e[12] = 0;
e[13] = 0;
e[14] = -2 * near * far * rd;
e[15] = 0;
return this;
};
</script>
<script type = 'text/javascript'>
function initContext(gl){
n = buffer_data_array.length / 5
var vertexColourBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColourBuffer)
var FSIZE = buffer_data_array.BYTES_PER_ELEMENT;
var a_Position = gl.getAttribLocation(gl.program, 'a_Position')
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0)
gl.enableVertexAttribArray(a_Position)
var a_Color = gl.getAttribLocation(gl.program, 'a_Color')
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, 2 * FSIZE)
gl.enableVertexAttribArray(a_Color)
u_basePointSize = gl.getUniformLocation(gl.program, 'u_basePointSize')
gl.uniform1f(u_basePointSize, particleSize)
u_Alpha = gl.getUniformLocation(gl.program, "u_Alpha")
gl.uniform1f(u_Alpha, alphaValue)
u_PaintFeatureScale = gl.getUniformLocation(gl.program, 'u_PaintFeatureScale')
gl.uniform1i(u_PaintFeatureScale, PaintFeatureScale)
gl.clearColor(1, 1, 1, 1);
if(bg_color == "dark"){
gl.clearColor(0, 0, 0, 1)
}
gl.disable(gl.DEPTH_TEST)
gl.enable(gl.BLEND)
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.clear(gl.COLOR_BUFFER_BIT);
return gl
}
function getContext(canvasWidget){
var names = ['webgl', 'experimental-webgl', 'webkit-3d', 'moz-webgl'];
for(var i=0; i<names.length; i++){
try{
var gl = canvasWidget.getContext(names[i])
}catch(e){}
if(gl){i=names.length}
}
var vshader = shadersFromScriptElement(gl, 'vertex-shader', gl.VERTEX_SHADER),
fshader = shadersFromScriptElement(gl, 'fragment-shader', gl.FRAGMENT_SHADER)
program = gl.createProgram();
gl.attachShader(program, vshader)
gl.attachShader(program, fshader)
gl.linkProgram(program)
gl.useProgram(program)
gl.program = program
return gl
}
function shadersFromScriptElement(gl, ID, type){
shaderScript = document.getElementById(ID)
var str = ''
var k = shaderScript.firstChild;
while(k){
if (k.nodeType == 3){
str += k.textContent;
}
k = k.nextSibling
}
var shader = gl.createShader(type)
gl.shaderSource(shader, str)
gl.compileShader(shader)
return shader
}
function toggleAllTypes(){
for (i=0;i<typesControlPanel.childElementCount;i++){
typesControlPanel.children[i].children[0].checked = toggleRadio.checked;
}
updateBuffer()
draw()
}
function updateBuffer(){
var buffer_data = [];
// first update indices to be used - for this read the category control panel radio buttons
current_indices = []
for(i=0;i<typesControlPanel.childElementCount;i++){
if(typesControlPanel.children[i].children[0].checked){
radio_type = typesControlPanel.children[i].children[0].id
current_indices = current_indices.concat(type_indices[radio_type])
}
}
// now just populate the buffer_data
if(colour_by == 'gene_expression'){
current_indices.forEach(function(index, i){
buffer_data.push(dr_coordinates[2 * index])
buffer_data.push(dr_coordinates[2 * index + 1])
buffer_data.push(gene_expression[index])
buffer_data.push(gene_expression[index])
buffer_data.push(gene_expression[index])
})
}else{
current_indices.forEach(function(index){
buffer_data.push(dr_coordinates[2 * index])
buffer_data.push(dr_coordinates[2 * index + 1])
buffer_data.push(category_type_colors[3 * index])
buffer_data.push(category_type_colors[3 * index + 1])
buffer_data.push(category_type_colors[3 * index + 2])
})
}
buffer_data_array = new Float32Array(buffer_data)
n = buffer_data_array.length / 5
}
function draw(){
if(bg_color == "white"){
gl_context.clearColor(1, 1, 1, 1)
}else{
gl_context.clearColor(0, 0, 0, 1)
}
gl_context.clear(gl_context.COLOR_BUFFER_BIT);
if(n > 0){
gl_context.bufferData(gl_context.ARRAY_BUFFER, buffer_data_array, gl_context.STATIC_DRAW)
gl_context.drawArrays(gl_context.POINTS, 0, n)
}
}
function setParticleSize(value){
particleSize = parseInt(value)
gl_context.uniform1f(u_basePointSize, particleSize)
updateBuffer()
draw()
}
function setAlpha(value){
alphaValue = parseInt(value) / 1000
gl_context.uniform1f(u_Alpha, alphaValue)
updateBuffer()
draw()
}
function setCanvasSize(value){
value = parseInt(value)
canvas.width = value
canvas.height = value
gl_context = getContext(canvas)
gl_context = initContext(gl_context)
gl_context.viewport(0, 0, canvas.width, canvas.height)
updateBuffer()
draw()
}
function setBackground(value){
bg_color = value;
draw()
}
function toggleCategoryAction(){
updateBuffer()
draw()
}
function updateCategories(value){
var request;
try {
request = new XMLHttpRequest();
}catch(e){
try{
request = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
request = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
alert('Your browser is too old. Update your browser!')
}
}
}
request.onreadystatechange = function(){
if (request.readyState == 4){
response = request.responseText
if(response == 'Password not correct'){document.body.innerHTML = "<h1>Wrong password. Refresh page an try again</h1>"}
response = response.split('&&');
typesControlPanel.innerHTML = response[0]
toggleRadio.checked = true;
reponse_colors = response[1].split(',');
reponse_indices = response[2].split(';');
category_type_colors = []
type_indices = [];
reponse_colors.forEach(function(val){
category_type_colors.push(parseFloat(val));
})
reponse_indices.forEach(function(indices){
try{
indices = indices.split('->');
var indices_name = indices[0],
indices_values = indices[1].split(',');
indices_array = [];
indices_values.forEach(function(val){
indices_array.push(parseInt(val))
})
type_indices[indices_name] = indices_array;
}catch(e){}
})
toggleCategoryAction()
}
}
queryString = "?category=" + value;
queryString = queryString + "&mot_de_pass=" + password;
request.open("GET", "fetch_category.php" + queryString, true)
request.send(null)
}
function getGeneExpression(caller){
value = caller.value;
caller_id = caller.id
if (caller.id == 'geneSymbolSelector'){
genelist_input.value = value
}else{
geneSymbolSelector.value = value
}
gene_expression = []
try {
request = new XMLHttpRequest();
}catch(e){
try{
request = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
request = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
alert('Your browser is too old. Update your browser!')
}
}
}
request.onreadystatechange = function(){
if (request.readyState == 4){
response = request.responseText.split(',');
gene_expression_scale = parseFloat(response[0]);
var r = response.shift();
response.forEach(function(val){
gene_expression.push(parseFloat(val))
})
if(colour_by == 'gene_expression'){
gl_context = getContext(canvas),
gl_context = initContext(gl_context);
toggleCategoryAction()
if(!isNaN(gene_expression_scale)){
expression_scale.innerHTML = "<canvas id ='scale_canvas' width = 200 height = 30></canvas><i>" + genelist_input.value + '</i>'
var scale_canvas = document.getElementById('scale_canvas'),
scale_context = scale_canvas.getContext('2d');
scale_gradient = scale_context.createLinearGradient(0, 0, 200, 0);
scale_gradient.addColorStop(0, 'blue');
scale_gradient.addColorStop(0.5, 'green');
scale_gradient.addColorStop(1, 'red');
scale_context.fillStyle = scale_gradient;
scale_context.fillRect(0, 20, scale_canvas.width, scale_canvas.height)
scale_context.fillStyle = 'black'
scale_context.fillText('0', 10, 10)
scale_context.fillText(parseInt(10 * gene_expression_scale) / 10, 180, 10)
}else{expression_scale.innerHTML = ""}
if (geneFamilySelector.value != 'All'){
if(gene_families[geneFamilySelector.value].indexOf(genelist_input.value) == -1){
expression_scale.innerHTML = 'Gene entered is not part of selected gene family!'
}
}
if (gene_list.indexOf(genelist_input.value) == -1){
expression_scale.innerHTML = 'Gene name mistyped or does not exist!'
}
if (genelist_input.value == ''){
expression_scale.innerHTML = "Choose a gene"
}
geneSymbolSelector_datalist.value = genelist_input.value
}
}
}
value = value.replace('/', "___")
queryString = "?gene_name=" + value;
request.open("GET", "fetch_gene_expression.php" + queryString, true)
request.send(null)
}
function setColourBy(val){
colour_by = val;
PaintFeatureScale = 1
if (colour_by == "cell_type"){
PaintFeatureScale = 0
}
if(colour_by == "gene_expression"){
getGeneExpression(genelist_input)
}else{
gl_context = getContext(canvas),
gl_context = initContext(gl_context);
toggleCategoryAction()
expression_scale.innerHTML = '';
}
}
function getCoordinates(value){
dr_coordinates = []
try {
request = new XMLHttpRequest();
}catch(e){
try{
request = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
request = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
alert('Your browser is too old. Update your browser!')
}
}
}
request.onreadystatechange = function(){
if (request.readyState == 4){
response = request.responseText.split(",")
response.forEach(function(val){dr_coordinates.push(parseFloat(val))})
if(canvas_init){
updateBuffer()
draw()
}
}
}
queryString = "?dr_name=" + value;
request.open("GET", "fetch_dr_coordinates.php" + queryString, true)
request.send(null)
}
function selectFamily(value){
geneSymbolSelector_innerHTML = "<select onchange = 'getGeneExpression(this)' id ='geneSymbolSelector'>"
if (value == 'All'){
gene_list.forEach(function(gene_name, i){
geneSymbolSelector_innerHTML = geneSymbolSelector_innerHTML + "<option value = '" + gene_name + "'>" + gene_name + "</option>"
})
}else{
family_genes = gene_families[value]
family_genes.forEach(function(gene_name, i){
geneSymbolSelector_innerHTML = geneSymbolSelector_innerHTML + "<option value = '" + gene_name + "'>" + gene_name + "</option>"
})
}
geneSymbolSelector_innerHTML = geneSymbolSelector_innerHTML + '</select>'
geneSymbolSelector.innerHTML = geneSymbolSelector_innerHTML
if (canvas_init){getGeneExpression(genelist_input)}
}
var category_type_colors = [],
type_indices = [],
gene_expression = [],
dr_coordinates = [],
categorySelectMenu = document.getElementById('categorySelectMenu'),
genelist_input = document.getElementById('genelist_input'),
expression_scale = document.getElementById('expression_scale'),
canvas = document.getElementById('canvas'),
typesControlPanel = document.getElementById('typesControlPanel'),
toggleRadio = document.getElementById('toggleRadio'),
geneFamilySelector = document.getElementById('geneFamilySelector'),
geneSymbolSelector = document.getElementById('geneSymbolSelector'),
particleSize = 5,
alphaValue = 1.0,
bg_color = "white",
n = 0,
particleSize = 2,
PaintFeatureScale = 0,
currentMaxExpression = 0,
buffer_data_array = null,
colour_by = "cell_types",
gene_expression_scale = 0,
canvas_init = false;
// population gene families
geneFamilySelector_innerHTML = "<option value = 'All'>All</option>"
for(var gene_family_name in gene_families){
geneFamilySelector_innerHTML = geneFamilySelector_innerHTML + "<option value = '" + gene_family_name + "'>" + gene_family_name + "</option>"
}
geneFamilySelector.innerHTML = geneFamilySelector_innerHTML
selectFamily('All')
getCoordinates(first_dr)
updateCategories(categorySelectMenu.value)
updateBuffer()
// create the renderer
var gl_context = getContext(canvas),
gl_context = initContext(gl_context);
draw()
canvas_init = true;
// safari does not support datalist
// see at https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_datalist
var curTxt=document.createElement('div');
curTxt.id="cursorText";
document.body.appendChild(curTxt);
canvas.addEventListener('mousemove', function(event){
var canvasRect = canvas.getBoundingClientRect();
var selectedIndex = false;
Xc = 2*(event.clientX - canvasRect.x) / canvas.width - 1;
Yc = -2*(event.clientY - canvasRect.y) / canvas.height + 1;
for(var k=0; k<dr_coordinates.length/2;k++){
dd = Math.abs(Xc - dr_coordinates[2*k]) + Math.abs(Yc - dr_coordinates[2*k + 1])
if (dd < .003){
selectedIndex = k
break;
}
}
var selectedCellType = ""
for (var xy_cell_type in type_indices){
if (type_indices[xy_cell_type].includes(selectedIndex)){
selectedCellType = xy_cell_type
break
}
}
curTxt.innerHTML = selectedCellType
curTxt.style.left = event.pageX + 5 + "px"
curTxt.style.top = event.pageY - curTxt.offsetHeight + "px"
})
</script>
<div style="float: clear;""><hr><span style="font-size:0.8em;">This data portal was created using the web_portal tool (<a href="https://github.com/DoruMP/Fast-data-portals-for-scRNAseq-data">github link</a>) developed by Dorin-Mirel Popescu</span><hr></div>
</body>
</html>

View file

@ -0,0 +1,37 @@
<?php
$mot_de_pass = $_GET['mot_de_pass'];
$password = "b3mZ5GVYeRZEvk8ctsEk";
if ($mot_de_pass != $password){
exit('Password not correct');
}
$category_name = $_GET["category"];
$color_key_file = $category_name . "_color_key.csv";
$color_key_file = "./categories/" . $color_key_file;
$color_key_file = fopen($color_key_file, "r");
$line = fgets($color_key_file );
$data_string = "";
while (($line = fgets($color_key_file)) !== false){
$col_key = explode(",", $line);
$cell_name = $col_key[0];
$cell_col = $col_key[1];
$button_html = str_replace('cell_name', str_replace('"', "", $cell_name), "<div style='background-color: cell_color;'><input type = 'checkbox' onchange='toggleCategoryAction()' name = 'cellTypeBtn' id='cell_name' checked /><label for = 'cell_name'> cell_name</label></div>");
$button_html = str_replace('cell_color', str_replace('"', "", $cell_col), $button_html);
$data_string = $data_string . $button_html;
}
fclose($color_key_file);
$categories_colors_file = "./categories/" . $category_name . "_colors";
$categories_colors_file = fopen($categories_colors_file, "r");
$categories_colors = fgets($categories_colors_file);
fclose($categories_colors_file);
$data_string = $data_string . "&&" . $categories_colors;
$categories_indices_file = "./categories/" . $category_name . "_indices";
$categories_indices_file = fopen($categories_indices_file, "r");
$categories_indices = fgets($categories_indices_file);
fclose($categories_indices_file);
$data_string = $data_string . "&&" . $categories_indices;
echo $data_string;
?>

View file

@ -0,0 +1,7 @@
<?php
$dr_fname = "./dr/" . $_GET["dr_name"] . "_coordinates";
$dr_file = fopen($dr_fname, 'r');
$dr_array = fgets($dr_file);
fclose($dr_file);
echo $dr_array;
?>

View file

@ -0,0 +1,7 @@
<?php
$gene_name = $_GET["gene_name"];
$gene_expression_file = './genes/' . $gene_name;
$gene_expression_file = fopen($gene_expression_file, 'r');
$gene_expression = fgets($gene_expression_file);
echo $gene_expression;
?>

View file

@ -0,0 +1,12 @@
f = open("fetch_category.php", "r")
content = f.readlines()
f.close()
import string
import random
material = string.ascii_lowercase+string.ascii_uppercase+"123456789"
pswd = "".join([random.choice(material) for k in range(20)])
with open("password.txt", "w") as pswd_file: pswd_file.write(pswd);
pswd = '\t$password = "{pswd}";\n'.format(pswd = pswd)
content[2] = pswd
content = "".join(content)
with open("fetch_category.php", "w") as new_fetch:new_fetch.write(content);

View file

@ -0,0 +1,752 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Gene expression web portal</title>
<meta name="description" content="Gene expression web portal for single cell RNA sequencing data made for the Human Cell Atlas at Newcastle University">
<meta name="author" content="Dorin-Mirel Popescu">
<style>
body {
font-family: Avenir, Arial, sans-serif;
}
#div_left {
float: left;
}
#canvasdiv {
overflow-x: scroll;
overflow-y: scroll;
max-height: 90vh;
}
#typesControlPanel {
height: 25em;
overflow-y: auto;
}
#cursorText{
position:absolute;
background-color: black;
color : white;
}
</style>
</head>
<body>
<?php
$password = 'cucurucu';
echo "<script type = 'text/javascript'>";
echo "var password = prompt('Introduce password:')";
echo "</script>";
?>
<div id = "div_left">
<form>
<fieldset>
<legend><b>Visualisation options</b></legend>
<label for = 'particleSizeBar'>Particle size: </label>
<input type='range' name = 'particleSizeBar' min = .3 max = 7 step=0.1 oninput='setParticleSize(value)' value = 2 /><br/>
<label for = 'alphaInput'>Transparency: </label>
<input type='range' name = 'alphaInput' min = 0 max = 1000 oninput='setAlpha(value)' value = 1000 /><br/>
<label for = 'canvasSizeInput'>Canvas size: </label>
<input type='range' name = 'canvasSizeInput' min = 200 max = 2000 oninput='setCanvasSize(value)' value = 500 /><br/>
</fieldset>
</form>
<form>
<fieldset>
<legend><b>Cell types</b></legend>
<div>
<div>
Select category: <select id='categorySelectMenu' onchange = 'updateCategories(value)'>
<?php
$categories_file = fopen("./categories/categories_key", "r");
$categories_content = fgets($categories_file);
fclose($categories_file);
$categories = explode(";", $categories_content);
foreach($categories as $category){
$category_fields = explode("->", $category);
$category_name = $category_fields[0];
$category_value = $category_fields[1];
echo "<option value='" . $category_value . "'>" . $category_name . "</option>";
}
?>
</select>
</div>
</div>
<label for='toggleRadio'><input type='checkbox' name = 'toggleRadio' id='toggleRadio' onchange='toggleAllTypes()' checked />Show all</label>
<div id='typesControlPanel'>
</div>
</fieldset>
</form>
</div>
<div id = "div_right">
<div>
<b>Colour by:</b>
<label for='colourType_t'><input type='radio' name='colourType' id='colourType_t' onchange='setColourBy(value)' value='cell_type' checked />Cell type</label>
<label for='colourType_g'><input type='radio' name='colourType' id='colourType_g' onchange='setColourBy(value)' value='gene_expression' />Gene expression</label>
</div>
<table id = "geneSelectorTable">
<tr>
<td>
<label for='geneFamilySelector'>Gene family:</label>
</td>
<td>
<select name='geneFamilySelector' id='geneFamilySelector' onchange='selectFamily(value)'>
</select>
</td>
</tr>
<tr>
<td>
<label for='geneSymbolSelector'>Gene symbol:</label>
</td>
<td>
<input type = 'text' id='genelist_input' name = 'geneSymbolSelector_datalist' list='geneSymbolSelector_datalist' onchange='getGeneExpression(this)'>
<datalist id = 'geneSymbolSelector_datalist'>
<select onchange = 'getGeneExpression(this)' id ='geneSymbolSelector'></select>
</datalist>
</td>
</tr>
</table>
<label for = 'bgColorRadio_white'><input id = 'bgColorRadio_white' name = "bgColorRadio" type = "radio" value = 'white' onchange='setBackground(value)' checked/>White background </label>
<label for = 'bgColorRadio_dark'><input id = 'bgColorRadio_dark' name = "bgColorRadio" type = "radio" value = 'dark' onchange='setBackground(value)' />Dark background </label>
<br/><span id='expression_scale'></span>
<div>
Choose coordinates: <select onchange = 'getCoordinates(value)'>
<?php
$dr_file = fopen("./dr/dr_key", "r");
$dr_content = fgets($dr_file);
fclose($dr_file);
$dr_cats = explode(";", $dr_content);
foreach($dr_cats as $dr_cat){
echo 1;
$dr_fields = explode("->", $dr_cat);
$dr_name = $dr_fields[0];
echo "<option value='" . $dr_name . "'>" . $dr_name . "</option>";
}
?>
</select>
</div>
<div id='canvasdiv'><canvas id='canvas' width=500 height=500></canvas></div>
</div>
<script id='vertex-shader' type='x-shader/x-fragment'>
attribute vec4 a_Position;
attribute vec3 a_Color;
uniform float u_basePointSize;
uniform float u_Alpha;
uniform int u_PaintFeatureScale;
varying vec4 v_Color;
void main() {
gl_Position = a_Position;
gl_PointSize = u_basePointSize;
if (u_PaintFeatureScale == 0){
v_Color = vec4(a_Color, u_Alpha);
}
else{
float r = 0.0;
float g = 0.0;
float b = 0.0;
r = max(0.0, 2.0 * a_Color.r - 1.0);
b = max(0.0, 2.0 * (1.0 - a_Color.r) - 1.0);
g = 1.0 - 2.0 * abs(a_Color.r - 0.5);
v_Color = vec4(r, g, b, u_Alpha);
}
}
</script>
<script id ='fragment-shader' type='x-shader/x-fragment'>
precision mediump float;
varying vec4 v_Color;
void main() {
float r = 0.0;
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
r = dot(cxy, cxy);
if (r > 1.0){
discard;
}
gl_FragColor = v_Color;
}
</script>
<?php
echo "<script type = 'text/javascript'>";
$gene_families_file = fopen("./genes/gene_lists", "r");
$gene_families_content = fgets($gene_families_file);
fclose($gene_families_file);
echo $gene_families_content;
$dr_file = fopen("./dr/dr_key", "r");
$dr_content = fgets($dr_file);
fclose($dr_file);
$dr_cats = explode(";", $dr_content);
$first_dr = explode('->', $dr_cats[0])[0];
echo "first_dr = '" . $first_dr . "'";
echo "</script>";
?>
<script type = 'text/javascript'>
var Matrix4 = function(opt_src) {
var i, s, d;
if (opt_src && typeof opt_src === 'object' && opt_src.hasOwnProperty('elements')) {
s = opt_src.elements;
d = new Float32Array(16);
for (i = 0; i < 16; ++i) {
d[i] = s[i];
}
this.elements = d;
} else {
this.elements = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
}
};
Matrix4.prototype.setTranslate = function(x, y, z) {
var e = this.elements;
e[0] = 1; e[4] = 0; e[8] = 0; e[12] = x;
e[1] = 0; e[5] = 1; e[9] = 0; e[13] = y;
e[2] = 0; e[6] = 0; e[10] = 1; e[14] = z;
e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1;
return this;
};
Matrix4.prototype.setLookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
var e, fx, fy, fz, rlf, sx, sy, sz, rls, ux, uy, uz;
fx = centerX - eyeX;
fy = centerY - eyeY;
fz = centerZ - eyeZ;
// Normalize f.
rlf = 1 / Math.sqrt(fx*fx + fy*fy + fz*fz);
fx *= rlf;
fy *= rlf;
fz *= rlf;
// Calculate cross product of f and up.
sx = fy * upZ - fz * upY;
sy = fz * upX - fx * upZ;
sz = fx * upY - fy * upX;
// Normalize s.
rls = 1 / Math.sqrt(sx*sx + sy*sy + sz*sz);
sx *= rls;
sy *= rls;
sz *= rls;
// Calculate cross product of s and f.
ux = sy * fz - sz * fy;
uy = sz * fx - sx * fz;
uz = sx * fy - sy * fx;
// Set to this.
e = this.elements;
e[0] = sx;
e[1] = ux;
e[2] = -fx;
e[3] = 0;
e[4] = sy;
e[5] = uy;
e[6] = -fy;
e[7] = 0;
e[8] = sz;
e[9] = uz;
e[10] = -fz;
e[11] = 0;
e[12] = 0;
e[13] = 0;
e[14] = 0;
e[15] = 1;
// Translate.
return this.translate(-eyeX, -eyeY, -eyeZ);
};
Matrix4.prototype.translate = function(x, y, z) {
var e = this.elements;
e[12] += e[0] * x + e[4] * y + e[8] * z;
e[13] += e[1] * x + e[5] * y + e[9] * z;
e[14] += e[2] * x + e[6] * y + e[10] * z;
e[15] += e[3] * x + e[7] * y + e[11] * z;
return this;
};
Matrix4.prototype.setPerspective = function(fovy, aspect, near, far) {
var e, rd, s, ct;
if (near === far || aspect === 0) {
throw 'null frustum';
}
if (near <= 0) {
throw 'near <= 0';
}
if (far <= 0) {
throw 'far <= 0';
}
fovy = Math.PI * fovy / 180 / 2;
s = Math.sin(fovy);
if (s === 0) {
throw 'null frustum';
}
rd = 1 / (far - near);
ct = Math.cos(fovy) / s;
e = this.elements;
e[0] = ct / aspect;
e[1] = 0;
e[2] = 0;
e[3] = 0;
e[4] = 0;
e[5] = ct;
e[6] = 0;
e[7] = 0;
e[8] = 0;
e[9] = 0;
e[10] = -(far + near) * rd;
e[11] = -1;
e[12] = 0;
e[13] = 0;
e[14] = -2 * near * far * rd;
e[15] = 0;
return this;
};
</script>
<script type = 'text/javascript'>
function initContext(gl){
n = buffer_data_array.length / 5
var vertexColourBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColourBuffer)
var FSIZE = buffer_data_array.BYTES_PER_ELEMENT;
var a_Position = gl.getAttribLocation(gl.program, 'a_Position')
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0)
gl.enableVertexAttribArray(a_Position)
var a_Color = gl.getAttribLocation(gl.program, 'a_Color')
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, 2 * FSIZE)
gl.enableVertexAttribArray(a_Color)
u_basePointSize = gl.getUniformLocation(gl.program, 'u_basePointSize')
gl.uniform1f(u_basePointSize, particleSize)
u_Alpha = gl.getUniformLocation(gl.program, "u_Alpha")
gl.uniform1f(u_Alpha, alphaValue)
u_PaintFeatureScale = gl.getUniformLocation(gl.program, 'u_PaintFeatureScale')
gl.uniform1i(u_PaintFeatureScale, PaintFeatureScale)
gl.clearColor(1, 1, 1, 1);
if(bg_color == "dark"){
gl.clearColor(0, 0, 0, 1)
}
gl.disable(gl.DEPTH_TEST)
gl.enable(gl.BLEND)
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.clear(gl.COLOR_BUFFER_BIT);
return gl
}
function getContext(canvasWidget){
var names = ['webgl', 'experimental-webgl', 'webkit-3d', 'moz-webgl'];
for(var i=0; i<names.length; i++){
try{
var gl = canvasWidget.getContext(names[i])
}catch(e){}
if(gl){i=names.length}
}
var vshader = shadersFromScriptElement(gl, 'vertex-shader', gl.VERTEX_SHADER),
fshader = shadersFromScriptElement(gl, 'fragment-shader', gl.FRAGMENT_SHADER)
program = gl.createProgram();
gl.attachShader(program, vshader)
gl.attachShader(program, fshader)
gl.linkProgram(program)
gl.useProgram(program)
gl.program = program
return gl
}
function shadersFromScriptElement(gl, ID, type){
shaderScript = document.getElementById(ID)
var str = ''
var k = shaderScript.firstChild;
while(k){
if (k.nodeType == 3){
str += k.textContent;
}
k = k.nextSibling
}
var shader = gl.createShader(type)
gl.shaderSource(shader, str)
gl.compileShader(shader)
return shader
}
function toggleAllTypes(){
for (i=0;i<typesControlPanel.childElementCount;i++){
typesControlPanel.children[i].children[0].checked = toggleRadio.checked;
}
updateBuffer()
draw()
}
function updateBuffer(){
var buffer_data = [];
// first update indices to be used - for this read the category control panel radio buttons
current_indices = []
for(i=0;i<typesControlPanel.childElementCount;i++){
if(typesControlPanel.children[i].children[0].checked){
radio_type = typesControlPanel.children[i].children[0].id
current_indices = current_indices.concat(type_indices[radio_type])
}
}
// now just populate the buffer_data
if(colour_by == 'gene_expression'){
current_indices.forEach(function(index, i){
buffer_data.push(dr_coordinates[2 * index])
buffer_data.push(dr_coordinates[2 * index + 1])
buffer_data.push(gene_expression[index])
buffer_data.push(gene_expression[index])
buffer_data.push(gene_expression[index])
})
}else{
current_indices.forEach(function(index){
buffer_data.push(dr_coordinates[2 * index])
buffer_data.push(dr_coordinates[2 * index + 1])
buffer_data.push(category_type_colors[3 * index])
buffer_data.push(category_type_colors[3 * index + 1])
buffer_data.push(category_type_colors[3 * index + 2])
})
}
buffer_data_array = new Float32Array(buffer_data)
n = buffer_data_array.length / 5
}
function draw(){
if(bg_color == "white"){
gl_context.clearColor(1, 1, 1, 1)
}else{
gl_context.clearColor(0, 0, 0, 1)
}
gl_context.clear(gl_context.COLOR_BUFFER_BIT);
if(n > 0){
gl_context.bufferData(gl_context.ARRAY_BUFFER, buffer_data_array, gl_context.STATIC_DRAW)
gl_context.drawArrays(gl_context.POINTS, 0, n)
}
}
function setParticleSize(value){
particleSize = parseInt(value)
gl_context.uniform1f(u_basePointSize, particleSize)
updateBuffer()
draw()
}
function setAlpha(value){
alphaValue = parseInt(value) / 1000
gl_context.uniform1f(u_Alpha, alphaValue)
updateBuffer()
draw()
}
function setCanvasSize(value){
value = parseInt(value)
canvas.width = value
canvas.height = value
gl_context = getContext(canvas)
gl_context = initContext(gl_context)
gl_context.viewport(0, 0, canvas.width, canvas.height)
updateBuffer()
draw()
}
function setBackground(value){
bg_color = value;
draw()
}
function toggleCategoryAction(){
updateBuffer()
draw()
}
function updateCategories(value){
var request;
try {
request = new XMLHttpRequest();
}catch(e){
try{
request = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
request = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
alert('Your browser is too old. Update your browser!')
}
}
}
request.onreadystatechange = function(){
if (request.readyState == 4){
response = request.responseText
if(response == 'Password not correct'){document.body.innerHTML = "<h1>Wrong password. Refresh page an try again</h1>"}
response = response.split('&&');
typesControlPanel.innerHTML = response[0]
toggleRadio.checked = true;
reponse_colors = response[1].split(',');
reponse_indices = response[2].split(';');
category_type_colors = []
type_indices = [];
reponse_colors.forEach(function(val){
category_type_colors.push(parseFloat(val));
})
reponse_indices.forEach(function(indices){
try{
indices = indices.split('->');
var indices_name = indices[0],
indices_values = indices[1].split(',');
indices_array = [];
indices_values.forEach(function(val){
indices_array.push(parseInt(val))
})
type_indices[indices_name] = indices_array;
}catch(e){}
})
toggleCategoryAction()
}
}
queryString = "?category=" + value;
queryString = queryString + "&mot_de_pass=" + password;
request.open("GET", "fetch_category.php" + queryString, true)
request.send(null)
}
function getGeneExpression(caller){
value = caller.value;
caller_id = caller.id
if (caller.id == 'geneSymbolSelector'){
genelist_input.value = value
}else{
geneSymbolSelector.value = value
}
gene_expression = []
try {
request = new XMLHttpRequest();
}catch(e){
try{
request = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
request = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
alert('Your browser is too old. Update your browser!')
}
}
}
request.onreadystatechange = function(){
if (request.readyState == 4){
response = request.responseText.split(',');
gene_expression_scale = parseFloat(response[0]);
var r = response.shift();
response.forEach(function(val){
gene_expression.push(parseFloat(val))
})
if(colour_by == 'gene_expression'){
gl_context = getContext(canvas),
gl_context = initContext(gl_context);
toggleCategoryAction()
if(!isNaN(gene_expression_scale)){
expression_scale.innerHTML = "<canvas id ='scale_canvas' width = 200 height = 30></canvas><i>" + genelist_input.value + '</i>'
var scale_canvas = document.getElementById('scale_canvas'),
scale_context = scale_canvas.getContext('2d');
scale_gradient = scale_context.createLinearGradient(0, 0, 200, 0);
scale_gradient.addColorStop(0, 'blue');
scale_gradient.addColorStop(0.5, 'green');
scale_gradient.addColorStop(1, 'red');
scale_context.fillStyle = scale_gradient;
scale_context.fillRect(0, 20, scale_canvas.width, scale_canvas.height)
scale_context.fillStyle = 'black'
scale_context.fillText('0', 10, 10)
scale_context.fillText(parseInt(10 * gene_expression_scale) / 10, 180, 10)
}else{expression_scale.innerHTML = ""}
if (geneFamilySelector.value != 'All'){
if(gene_families[geneFamilySelector.value].indexOf(genelist_input.value) == -1){
expression_scale.innerHTML = 'Gene entered is not part of selected gene family!'
}
}
if (gene_list.indexOf(genelist_input.value) == -1){
expression_scale.innerHTML = 'Gene name mistyped or does not exist!'
}
if (genelist_input.value == ''){
expression_scale.innerHTML = "Choose a gene"
}
geneSymbolSelector_datalist.value = genelist_input.value
}
}
}
value = value.replace('/', "___")
queryString = "?gene_name=" + value;
request.open("GET", "fetch_gene_expression.php" + queryString, true)
request.send(null)
}
function setColourBy(val){
colour_by = val;
PaintFeatureScale = 1
if (colour_by == "cell_type"){
PaintFeatureScale = 0
}
if(colour_by == "gene_expression"){
getGeneExpression(genelist_input)
}else{
gl_context = getContext(canvas),
gl_context = initContext(gl_context);
toggleCategoryAction()
expression_scale.innerHTML = '';
}
}
function getCoordinates(value){
dr_coordinates = []
try {
request = new XMLHttpRequest();
}catch(e){
try{
request = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
request = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
alert('Your browser is too old. Update your browser!')
}
}
}
request.onreadystatechange = function(){
if (request.readyState == 4){
response = request.responseText.split(",")
response.forEach(function(val){dr_coordinates.push(parseFloat(val))})
if(canvas_init){
updateBuffer()
draw()
}
}
}
queryString = "?dr_name=" + value;
request.open("GET", "fetch_dr_coordinates.php" + queryString, true)
request.send(null)
}
function selectFamily(value){
geneSymbolSelector_innerHTML = "<select onchange = 'getGeneExpression(this)' id ='geneSymbolSelector'>"
if (value == 'All'){
gene_list.forEach(function(gene_name, i){
geneSymbolSelector_innerHTML = geneSymbolSelector_innerHTML + "<option value = '" + gene_name + "'>" + gene_name + "</option>"
})
}else{
family_genes = gene_families[value]
family_genes.forEach(function(gene_name, i){
geneSymbolSelector_innerHTML = geneSymbolSelector_innerHTML + "<option value = '" + gene_name + "'>" + gene_name + "</option>"
})
}
geneSymbolSelector_innerHTML = geneSymbolSelector_innerHTML + '</select>'
geneSymbolSelector.innerHTML = geneSymbolSelector_innerHTML
if (canvas_init){getGeneExpression(genelist_input)}
}
var category_type_colors = [],
type_indices = [],
gene_expression = [],
dr_coordinates = [],
categorySelectMenu = document.getElementById('categorySelectMenu'),
genelist_input = document.getElementById('genelist_input'),
expression_scale = document.getElementById('expression_scale'),
canvas = document.getElementById('canvas'),
typesControlPanel = document.getElementById('typesControlPanel'),
toggleRadio = document.getElementById('toggleRadio'),
geneFamilySelector = document.getElementById('geneFamilySelector'),
geneSymbolSelector = document.getElementById('geneSymbolSelector'),
particleSize = 5,
alphaValue = 1.0,
bg_color = "white",
n = 0,
particleSize = 2,
PaintFeatureScale = 0,
currentMaxExpression = 0,
buffer_data_array = null,
colour_by = "cell_types",
gene_expression_scale = 0,
canvas_init = false;
// population gene families
geneFamilySelector_innerHTML = "<option value = 'All'>All</option>"
for(var gene_family_name in gene_families){
geneFamilySelector_innerHTML = geneFamilySelector_innerHTML + "<option value = '" + gene_family_name + "'>" + gene_family_name + "</option>"
}
geneFamilySelector.innerHTML = geneFamilySelector_innerHTML
selectFamily('All')
getCoordinates(first_dr)
updateCategories(categorySelectMenu.value)
updateBuffer()
// create the renderer
var gl_context = getContext(canvas),
gl_context = initContext(gl_context);
draw()
canvas_init = true;
var curTxt=document.createElement('div');
curTxt.id="cursorText";
document.body.appendChild(curTxt);
canvas.addEventListener('mousemove', function(event){
var canvasRect = canvas.getBoundingClientRect();
var selectedIndex = false;
Xc = 2*(event.clientX - canvasRect.x) / canvas.width - 1;
Yc = -2*(event.clientY - canvasRect.y) / canvas.height + 1;
for(var k=0; k<dr_coordinates.length/2;k++){
dd = Math.abs(Xc - dr_coordinates[2*k]) + Math.abs(Yc - dr_coordinates[2*k + 1])
if (dd < .003){
selectedIndex = k
break;
}
}
var selectedCellType = ""
for (var xy_cell_type in type_indices){
if (type_indices[xy_cell_type].includes(selectedIndex)){
selectedCellType = xy_cell_type
break
}
}
curTxt.innerHTML = selectedCellType
curTxt.style.left = event.pageX + 5 + "px"
curTxt.style.top = event.pageY - curTxt.offsetHeight + "px"
})
// safari does not support datalist
// see at https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_datalist
</script>
<div style="float: clear;""><hr><span style="font-size:0.8em;">This data portal was created using the web_portal tool (<a href="https://github.com/DoruMP/Fast-data-portals-for-scRNAseq-data">github link</a>) developed by Dorin-Mirel Popescu</span><hr></div>
</body>
</html>

View file

@ -0,0 +1 @@
b3mZ5GVYeRZEvk8ctsEk

View file

@ -0,0 +1,348 @@
args = commandArgs(trailingOnly=T)
python.addr = 'python'
# load the required libraries
library(Seurat)
library(plyr)
library(dplyr)
library(RColorBrewer)
library(methods)
options_file = args[1]
##########################################################################################
##########################################################################################
##########################################################################################
# FUNCTIONS
# a function to convert hex colours to subunit rgb values - that are red by WebGL
hex_to_floats= function(hex_str){
red = round(strtoi(paste("0x", substr(x=hex_str, start=2, stop=3), sep = "")) / 255, digits=2)
green = round(strtoi(paste("0x", substr(x=hex_str, start=4, stop=5), sep = "")) / 255, digits=2)
blue = round(strtoi(paste("0x", substr(x=hex_str, start=6, stop=7), sep = "")) / 255, digits=2)
paste(c(red, green, blue), collapse = ",")
}
##########################################################################################
##########################################################################################
##########################################################################################
# extract options
options_fobj = file(options_file)
options_val = readLines(options_fobj)
close(options_fobj)
# make file_name variable
file_name = gsub(" ", "", unlist(strsplit(options_val[1], ':'))[2])
# make output_folder variable
output_folder = gsub(" ", "", unlist(strsplit(options_val[2], ':'))[2])
# make dr coordinates pointers
dr_coordinates = gsub(" ", "", unlist(strsplit(options_val[3], ':'))[2])
dr_coordinates = unlist(lapply(unlist(strsplit(dr_coordinates, ';')), strsplit, "->"))
dr_names = dr_coordinates[seq(1, length(dr_coordinates), 2)]
dr_slots = dr_coordinates[seq(2, length(dr_coordinates), 2)]
# make categories pointers
categories = unlist(lapply(unlist(strsplit(options_val[4], ';')), strsplit, '->'))
categories_names = categories[seq(1, length(categories), 3)]
categories_slot = categories[seq(2, length(categories), 3)]
categories_cols = categories[seq(3, length(categories), 3)]
# make the output folder and the other folders
dir.create(output_folder)
gene_output_folder = file.path(output_folder, "genes")
categories_output_folder = file.path(output_folder, "categories")
dr_output_folder = file.path(output_folder, "dr")
dir.create(gene_output_folder)
dir.create(categories_output_folder)
dir.create(dr_output_folder)
# check file_mame extension
# if is RDS assume this is a Seurat object and go on
# if is h5ad then assume it is a scanpy object and get help form Python to extract the required data
file_name_extension = unlist(strsplit(file_name, "\\."))
file_name_extension = file_name_extension[length(file_name_extension)]
if (file_name_extension == 'h5ad'){ # handle a scanpy object
print('Handling a Scanpy object')
command = sprintf("%s scanpy_to_seurat.py %s", python.addr, options_file)
system(command, wait = T)
# read expression matrix - should include nUMI and nGene
expression_matrix = readMM(file.path(output_folder, 'expression.mtx'))
# read the gene names
gene_name_fobj = file(file.path(output_folder, 'gene_names.txt'))
gene_names = readLines(gene_name_fobj)
close(gene_name_fobj)
# add gene names as colnames to gene_expression
colnames(expression_matrix) = gene_names
# transpose the expression matrix
expression_matrix = t(expression_matrix)
# read dr data
dr_matrix = read.csv(file.path(output_folder, 'dr.csv'), header = F)
# read the categories
categories_matrix = read.csv(file.path(output_folder, 'categories.csv'), row.names = 1, check.names=FALSE)
# remove the files
file.remove(file.path(output_folder, 'expression.mtx'))
file.remove(file.path(output_folder, 'gene_names.txt'))
file.remove(file.path(output_folder, 'dr.csv'))
file.remove(file.path(output_folder, 'categories.csv'))
# extract nUMI and nGENE
nUMI = expression_matrix['nUMI', ]
nGene = expression_matrix['nGene', ]
# remove nUMI and nGene rows from the expression matrix
indices = which(rownames(expression_matrix) %in% c('nUMI', 'nGene'))
expression_matrix = expression_matrix[-c(indices), ]
}else{ # handle a seurat object
print('Handling a Seurat object')
print('Loading data ...')
seurat.obj = readRDS(file_name)
print('Data loaded')
# extract expression_matrix
expression_matrix = seurat.obj@data
# make the dr matrix
for(i in 1:length(dr_slots)){
dr_slot = dr_slots[i]
command = paste("dr_slot_data = seurat.obj@dr$", dr_slot, "@cell.embeddings", sep = "")
eval(parse(text = command))
if (i == 1){
dr_matrix = dr_slot_data
}else{
dr_matrix = cbind(dr_matrix, dr_slot_data)
}
}
# make the categories_matrix
for (i in 1:length(categories_slot)){
cat_slot = categories_slot[i]
command = paste("category_data = seurat.obj@meta.data$", cat_slot, sep = "")
eval(parse(text = command))
category_data = as.vector(category_data)
if(categories_cols[i] == "null"){
# randomly generate the colors
unique_cats = sort(as.vector(unique(category_data)))
cat_colours = sample(colorRampPalette(brewer.pal(12, "Paired"))(length(unique_cats)))
}else{
type.to.colour = read.csv(categories_cols[i])
unique_cats = as.vector(type.to.colour$CellTypes)
cat_colours = as.vector(type.to.colour$Colours)
}
cat_colours = mapvalues(x=category_data, from=unique_cats, to=cat_colours)
cat_data = data.frame(Labels = category_data, Colours = cat_colours)
colnames(cat_data) = c(categories_names[i], paste(categories_names[i], "_Colour", sep = ""))
if ( i == 1 ){
categories_matrix = cat_data
}else{
categories_matrix = cbind(categories_matrix, cat_data)
}
}
# extract nUMI and nGENE
nGene = seurat.obj@meta.data$nGene
nUMI = seurat.obj@meta.data$nUMI
}
# save color key for each category
# categories_names
# categories_slot
# categories_cols
for (i in 1:length(categories_names)){
category_name = categories_names[i]
category_col = paste(category_name, 'Colour', sep = '_')
category_slot = categories_slot[i]
category_tags = as.vector(categories_matrix[, category_name])
category_cols = as.vector(categories_matrix[, category_col])
category_unique = unique(category_tags)
cols_unique = mapvalues(x=category_unique, from = category_tags, to = category_cols, warn_missing=F)
# caol keys
color.key = data.frame(Categories = category_unique, Colours = cols_unique)
color_key_fname = paste(category_slot, "_color_key.csv", sep = '')
write.csv(color.key, file.path(categories_output_folder, color_key_fname), row.names=FALSE)
# color floats webgl-readable
float_colors = unlist(lapply(category_cols, hex_to_floats))
float_colors = paste(float_colors, collapse = ",")
float_colors_file = paste(category_slot, 'colors', sep = '_')
float_colors_file = file(file.path(categories_output_folder, float_colors_file), 'w')
writeLines(float_colors, float_colors_file)
close(float_colors_file)
# save category indices
cell.types.indices = ""
for(i in 1:length(category_unique)){
cell.label = category_unique[i]
cell.label.indices = which(category_tags %in% c(cell.label)) - 1
cell.label.indices = paste(cell.label.indices, collapse = ",")
assignment = paste(cell.label, cell.label.indices, sep = "->")
cell.types.indices = c(cell.types.indices, assignment)
}
cell.types.indices = paste(cell.types.indices, collapse = ";")
type_fname = paste(category_slot, 'indices', sep = '_')
cell.types.indices.file = file.path(categories_output_folder, type_fname)
cell.types.indices.file = file(cell.types.indices.file, "w")
writeLines(cell.types.indices, cell.types.indices.file)
close(cell.types.indices.file)
}
# save categories types key
# categories_names
# categories_slot
categories.menu.content = ""
for(i in 1:length(categories_names)){
category_name = categories_names[i]
category_slot = categories_slot[i]
category_arrow = paste(category_name, "->", category_slot, ";", sep = '')
categories.menu.content = paste(categories.menu.content, category_arrow, sep = "")
}
categories.menu.file = file.path(categories_output_folder, "categories_key")
categories.menu.file = file(categories.menu.file, "w")
writeLines(categories.menu.content, categories.menu.file)
close(categories.menu.file)
# save key to dr
#dr_names
#dr_slots
dr.menu.content = ""
for(i in 1:length(dr_names)){
dr_name = dr_names[i]
dr_slot = dr_slots[i]
dr_arrow = paste(dr_name, "->", dr_slot, ";", sep = "")
dr.menu.content = paste(dr.menu.content, dr_arrow, sep = "")
}
dr.menu.file = file.path(dr_output_folder, "dr_key")
dr.menu.file = file(dr.menu.file, "w")
writeLines(dr.menu.content, dr.menu.file)
close(dr.menu.file)
# save dr coordinates
#dr_names
#dr_slots
#dr_matrix
for(i in 0:(length(dr_names) - 1)){
dr_name = dr_names[i + 1]
start_ = 2*i + 1
end_ = 2*i + 2
coordinates = dr_matrix[, c(start_, end_)]
coordinates.x.q = mean(quantile(coordinates[, 1], c(.01, .99)))
coordinates.y.q = mean(quantile(coordinates[, 2], c(.01, .99)))
coordinates[, 1] = coordinates[, 1] - coordinates.x.q
coordinates[, 2] = coordinates[, 2] - coordinates.y.q
divide.x.at = quantile(coordinates[, 1], c(.99)) * 1.2
divide.y.at = quantile(coordinates[, 2], c(.99)) * 1.2
coordinates[, 1] = coordinates[, 1] / divide.x.at
coordinates[, 2] = coordinates[, 2] / divide.y.at
coordinates_ = c()
for(i in 1:dim(coordinates)[1]){
varx = round(coordinates[i, 1], digits = 3)
vary = round(coordinates[i, 2], digits = 3)
coordinates_ = c(coordinates_ ,paste(varx, vary, sep = ","))
}
coordinates = paste(coordinates_, collapse = ",")
coordinates.file = paste(dr_name, "coordinates", sep = "_")
coordinates.file = file.path(dr_output_folder, coordinates.file)
coordinates.file = file(coordinates.file, "w")
writeLines(coordinates, coordinates.file)
close(coordinates.file)
}
# save gene expression
# get all genes names in alphabetical order
gene_names = read.csv("genes.tsv", sep = "\t", header = F)
gene_names = as.vector(unique(gene_names$V2))
gene_names = sort(gene_names)
# read the hgnc data frame and keep just the columns relevant for gene symbol and gene family
hgnc = read.csv("./hgnc.csv", sep = '\t', row.names =NULL)
hgnc = hgnc[, c("symbol", "gene_family")]
# filter out any rows where the gene symbol is not found in the seurat genes or where the gene symbol is not part of any family
hgnc = hgnc[hgnc$symbol %in% gene_names, ]
hgnc = hgnc[!(hgnc$gene_family == ""), ]
# extract all gene families and arrange them in alphabetical order
gene.families = sort(unique(unlist(strsplit(as.vector(hgnc$gene_family), split="\\|"))))
gene.families.contents = rep("", length(gene.families))
names(gene.families.contents) = gene.families
# population an empty vector which has names set to gene families, with all the genes part of that family
for(j in 1:dim(hgnc)[1]){
gene.fam.concat =unlist(strsplit( as.vector(hgnc$gene_family)[j], split = "\\|"))
quoted.gene.symbol = as.vector(hgnc$symbol)[j]
for (k in 1:length(gene.fam.concat)){
gene.fam = gene.fam.concat[k]
if(gene.families.contents[gene.fam] != ""){
gene.families.contents[gene.fam] = paste(gene.families.contents[gene.fam], paste("'", quoted.gene.symbol, "'", sep = ""), sep = ",")
}else{
gene.families.contents[gene.fam] = as.character(paste("'", quoted.gene.symbol, "'", sep = ""))
}
}
}
# insert each gene family into double quotes - for js compatibility
gene.families = unlist(lapply(gene.families, function(gene.fam){paste('\"', gene.fam, '\"', sep = "")}))
# insert each gene name in single quotes - for js compatibility
gene_names = unlist(lapply(gene_names, function(gene.n){paste("'", gene.n, "'", sep = "")}))
gene_names = paste(gene_names, collapse = ",")
# create a javacript point to gene_list and populate it with all gene names
gene.list = sprintf("gene_list = [%s];", gene_names)
# create the javacript named array gene_familie and populate it with indices for all genes for each gene family
gene.list = paste(gene.list, "gene_families = [];", sep = "")
# loop over each gene family name and insert its gene indices in gene.list
for(k in 1:length(gene.families)){
gene.fam = gene.families[k]
gene.indices = as.vector(gene.families.contents[k])
gene.list = paste(gene.list, sprintf("gene_families[%s] = [%s];", gene.fam, gene.indices), sep = "")
}
gene.list.file = file.path(gene_output_folder, "gene_lists")
gene.list.file = file(gene.list.file, "w")
writeLines(gene.list, gene.list.file)
close(gene.list.file)
####### save gene expression files
gene_names = read.csv("genes.tsv", sep = "\t", header = F)
gene_names = as.vector(unique(gene_names$V2))
gene_names = sort(gene_names)
gene.expression.scale.limit = 1;
# loop though each gene name, get its expression and convert it to a color scale
# if gene name does not exists in the seurat object (has not passed filtering) save its expression as zeros
expression_matrix = as(expression_matrix, 'dgCMatrix')
for (i in 1:length(gene_names)){
gene_name = gene_names[i]
if (gene_name %in% rownames(expression_matrix)){
gene_expression = expression_matrix[gene_name, ]
}else{
gene_expression = rep(0, ncol(expression_matrix))
}
gene_expression.upper.limit = max(max(gene_expression), gene.expression.scale.limit)
gene_expression = gene_expression / gene_expression.upper.limit
gene_expression = lapply(gene_expression, function(val){round(val, digits = 2)})
gene_expression = unlist(gene_expression)
gene_expression = c(round(gene_expression.upper.limit, digits=1), gene_expression)
gene_expression = paste(gene_expression, collapse = ",")
gene_expression.fname = file.path(gene_output_folder, gsub(pattern="/", replacement="__", x=gene_name));
gene_expression.file = file(gene_expression.fname)
writeLines(gene_expression, gene_expression.file)
close(gene_expression.file)
print(sprintf("%s - %s", gene_name, i))
}
# add the nUMI and nGene
for (j in 1:2){
gene_name = c('nGene', 'nUMI')[j]
if (j == 'nGene'){
gene_expression = nGene
}else{
gene_expression = nUMI
}
gene_expression.upper.limit = max(gene_expression)
gene_expression = gene_expression / gene_expression.upper.limit
gene_expression = lapply(gene_expression, function(val){round(val, digits = 2)})
gene_expression = unlist(gene_expression)
gene_expression = c(round(gene_expression.upper.limit, digits=1), gene_expression)
gene_expression = paste(gene_expression, collapse = ",")
gene_expression.fname = file.path(gene_output_folder, gsub(pattern="/", replacement="__", x=gene_name));
gene_expression.file = file(gene_expression.fname)
writeLines(gene_expression, gene_expression.file)
close(gene_expression.file)
print(sprintf("%s - %s", gene_name, j))
}
# tar zip the output so it will be faster to download/upload between servers
print("Tar-zipping the output so it will be much faster for downloading/uploading operations between servers ...")
output_folder.arh = paste(output_folder, ".tar.gz", sep = "")
tar(output_folder.arh, files = output_folder, compression = 'gzip')
print("(The output is the tar.zip file which is much faster to download/upload than a folder with tens of thousands of files.)")
# remove the out folder
print("Deleting the output folder ...")
unlink(x=output_folder, recursive=T, force=T)
print("Ended beautifully ... ")

View file

@ -0,0 +1,16 @@
#!/bin/bash
#$ -cwd
#$ -N web_portal
#$ -V
#$ -l h_rt=23:59:59
#$ -l h_vmem=100G
if [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit 1
fi
Rscript web_portal.R $1
echo "End on `date`"