Commit 22912496 authored by Remi  PLANEL's avatar Remi PLANEL
Browse files

Merge branch 'cc-qtl' into 'master'

Cc qtl

See merge request !1
parents 1dc5239d 9077093c
Pipeline #62142 passed with stages
in 2 minutes and 13 seconds
......@@ -3,4 +3,5 @@ dist
node_modules
build/
.vscode
/lib
\ No newline at end of file
/lib
examples/genome-scan/data/*.csv
\ No newline at end of file
# tsconfig.json
# src
examples
\ No newline at end of file
{
"folders": [
{
"path": "."
}
],
"settings": {}
}
\ No newline at end of file
<html>
<head>
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
......
import { GeneData, GenomeBrowserData, GenomeBrowserState } from "../../scripts/types";
import { select, event } from "d3-selection";
import GenomeBrowser from "../../scripts/component/genome-browser";
import genomeBrowserLayout from "../../scripts/layout/genome-browser";
// import { GeneData, GenomeBrowserData, GenomeBrowserState } from "../../scripts/types";
import { select } from "d3-selection";
import { Types, genomeBrowserLayout, GenomeBrowser } from "bioviz-js";
import './style.css';
const width = 1500;
const height = 300;
const genomeBrowserComponent = GenomeBrowser();
const geneData: GeneData[] = [
const geneData: Types.GeneData[] = [
{
name: "gene 1",
strand: "-",
......@@ -68,7 +67,7 @@ const geneData: GeneData[] = [
];
const state: GenomeBrowserState = {
const state: Types.GenomeBrowserState = {
width: 1500,
chromosomeSize: 75000,
window: [20000, 26000],
......@@ -106,7 +105,7 @@ select("#zoom-out").on("click", function () {
*/
function draw() {
// Get the data
const computedGenomeBrowserData: GenomeBrowserData =
const computedGenomeBrowserData: Types.GenomeBrowserData =
genomeBrowserLayout(state, brushHandler, clickHandler);
// Convert the data to DOM objects
......@@ -116,15 +115,15 @@ function draw() {
}
function clickHandler([begin, end]: [number, number], state: GenomeBrowserState) {
function clickHandler([begin, end]: [number, number], state: Types.GenomeBrowserState) {
const centerGene = (end + begin) / 2;
const sizeWindow = state.window[1] - state.window[0];
state.window = [centerGene - sizeWindow / 2, centerGene + sizeWindow / 2];
draw();
}
function brushHandler(scale: any, state: GenomeBrowserState) {
if (!event.sourceEvent) return;
function brushHandler(scale: any, state: Types.GenomeBrowserState, event: any) {
if (!event || !event.sourceEvent) return;
if (event.selection) {
const { selection: [x1, x2] } = event;
const newwindow: [number, number] = [scale.invert(x1), scale.invert(x2)];
......
This diff is collapsed.
{
"name": "genome-browser",
"version": "0.0.1",
"description": "example for genome browser",
"main": "lib/main.js",
"scripts": {
"start": "parcel index.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Rémi Planel",
"license": "ISC",
"dependencies": {
"d3-selection": "^1.4.1",
"bioviz-js": "file:../.."
},
"devDependencies": {
"parcel-bundler": "^1.12.4",
"typescript": "^3.7.4"
}
}
<html>
<body>
<div class="genome-scan">
<div class="lod-score-chromosomes"></div>
<div class="qtl-coefficient" id="myDiv"></div>
<div class="haplotype"></div>
<div class="snps"></div>
<div class="snp"></div>
</div>
<div class="genome-scan-per-chr"></div>
<script src="./main.ts"></script>
</body>
</html>
// import { GenomeScanData, HaplotypeData, PlotCoefData, SnpsData, SnpData } from "bioviz-js";
import { select } from "d3-selection";
import { Types, GenomeScan, QtlCoefficient, Haplotype, Snps, Snp } from "bioviz-js";
// import GenomeScan from "../../scripts/component/qtl/genome-scan";
// import QtlCoef from "../../scripts/component/qtl/qtl-coefficient";
// import Haplotype from "../../scripts/component/qtl/haplotype";
// import Snps from "../../scripts/component/qtl/snps";
// import Snp from "../../scripts/component/qtl/snp";
import { csv } from "d3-fetch";
// Csv data file
const genomeScanFile = require('./data/lod_tab.csv');
const significanceThresholdsFile = require('./data/sifgnificance-thresholds.csv');
const qtlCoefCsv = require('./data/dat-plotcoef.csv');
const haplotypeCsv = require('./data/dat_plot_haplo.csv');
const snpsCsv = require('./data/dat_plot_snps.csv');
const snpCsv = require("./data/dat_plot_snp_boxplot.csv");
// Code
Promise.all([
csv(genomeScanFile),
csv(significanceThresholdsFile),
csv(qtlCoefCsv),
csv(haplotypeCsv),
csv(snpsCsv),
csv(snpCsv),
]).then(([genomeScanData, significanceThresholds, rawPlotCoefData, rawHaplotypeData, rawSnpsData, rawSnpData]) => {
// Plot component
const genomeScan = GenomeScan();
const qtlCoefPlot = QtlCoefficient();
const haplotypePlot = Haplotype();
const snpsPlot = Snps();
const snpPlot = Snp();
// Data
const haplotypeData: Types.HaplotypeData[] = rawHaplotypeData.map(item => ({
...item,
Phenotype: parseFloat(item.Phenotype),
Haplotype: item.Haplotype,
Line: item.Line,
}))
const data: Types.GenomeScanData = {
lod_score_per_chromosome: genomeScanData.map(item => ({
...item,
pos: parseInt(item.pos),
chr: item.chr,
marker: item.marker,
lod: parseFloat(item.lod)
})),
significance_thresholds: significanceThresholds.map(item => ({
...item,
significance: parseFloat(item.significance),
threshold: parseFloat(item.threshold)
})),
};
const plotCoefData: Types.PlotCoefData[] = rawPlotCoefData.map(item => ({
...item,
marker: item.marker,
chr: item.chr,
pos: parseFloat(item.pos),
lod: parseFloat(item.lod),
A: parseFloat(item.A),
B: parseFloat(item.B),
C: parseFloat(item.C),
D: parseFloat(item.D),
E: parseFloat(item.E),
F: parseFloat(item.F),
G: parseFloat(item.D),
H: parseFloat(item.H),
}));
const snpsData: Types.SnpsData[] = rawSnpsData.map(item => ({
...item,
snp_id: item.snp_id,
chr: item.chr,
pos: parseFloat(item.pos),
lod: parseFloat(item.lod)
}));
const snpData: Types.SnpData[] = rawSnpData.map(item => {
return {
...item,
line: item.line,
phenotype: parseFloat(item.phenotype),
genotype: item.genotype,
strains: item.strains
}
})
select(".lod-score-chromosomes").datum(data).call(genomeScan);
select(".qtl-coefficient").datum(plotCoefData).call(qtlCoefPlot);
select(".haplotype").datum(haplotypeData).call(haplotypePlot);
select(".snps").datum(snpsData).call(snpsPlot);
select(".snp").datum(snpData).call(snpPlot);
})
This diff is collapsed.
{
"name": "genome-scan",
"version": "0.0.1",
"description": "Genome scan example",
"main": "main.ts",
"scripts": {
"start": "parcel index.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Rémi Planel",
"license": "ISC",
"dependencies": {
"bioviz-js": "file:../..",
"typescript": "^3.7.4"
},
"devDependencies": {
"parcel-bundler": "^1.12.4"
}
}
import PhylogramLayout from "../../scripts/layout/phylogram";
import CladogramLayout from "../../scripts/layout/cladogram";
import { RawPhyloTreeNode, } from "../../scripts/types";
import { select, event } from "d3-selection";
import Phylotree from "../../scripts/component/tree/phylotree";
import { cluster, hierarchy } from "d3-hierarchy";
import { defaultSeparation } from "../../scripts/layout/phylotree";
import { Types, PhylogramLayout, CladogramLayout, Phylotree } from "bioviz-js";
// CSS
import '../../styles/phylotree.css';
import './styles/phylotree.css';
// Code
const phylotreeComponent = Phylotree();
const data: RawPhyloTreeNode = {
const data: Types.RawPhyloTreeNode = {
"name": "",
branchLength: 0,
node: { r: 0 },
......@@ -89,7 +84,6 @@ function update(container) {
// Attach event to select button
select("#tree-layout-select").on("change", () => {
console.log(event);
if (event.srcElement.value === "phylogram") {
isPhylogram = true;
update(container)
......
This diff is collapsed.
{
"name": "phylotree",
"version": "0.0.1",
"description": "example for phylotree",
"main": "lib/main.js",
"scripts": {
"start": "parcel index.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Rémi Planel",
"license": "ISC",
"dependencies": {
"bioviz-js": "file:../.."
},
"devDependencies": {
"parcel-bundler": "^1.12.4"
}
}
This diff is collapsed.
......@@ -2,11 +2,11 @@
"name": "bioviz-js",
"version": "0.1.3",
"description": "Library to visualize biological data",
"main": "./lib/index.js",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"repository": "git@gitlab.pasteur.fr:rplanel/bioviz-js.git",
"author": "Remi Planel <rplanel@pasteur.fr>",
"license": "MIT",
"types": "./lib/index.d.ts",
"files": [
"lib/**/*"
],
......@@ -17,41 +17,41 @@
"visualization"
],
"scripts": {
"prepare": "npm run compile",
"prepublishOnly": "npm run test && npm run lint",
"preversion": "npm run lint",
"prepare": "npm run build",
"prepublishOnly": "yarn test && yarn lint",
"preversion": "yarn lint",
"version": "git add -A src",
"postversion": "git push && git push --tags",
"dev": "parcel src/scripts/main-genome-browser.ts",
"start-genome-browser": "parcel src/examples/genome-browser/index.html",
"start-phylotree": "parcel src/examples/phylotree/index.html",
"watch": "parcel watch src/scripts/main-genome-browser.ts",
"build": "parcel build src/scripts/main-genome-browser.ts",
"compile": "tsc",
"build": "tsc",
"watch-ts": "tsc -w",
"lint": "tslint -p tsconfig.json",
"test": "jest"
},
"devDependencies": {
"@types/jest": "^24.0.13",
"docusaurus-init": "^1.11.1",
"jest": "^24.8.0",
"@types/jest": "^26.0.15",
"@types/node": "^14.14.10",
"docusaurus-init": "^1.14.1",
"jest": "^27.0.4",
"rxjs-tslint": "^0.1.7",
"ts-jest": "^24.0.2",
"typescript": "^3.4.1"
"ts-jest": "^27.0.4",
"typescript": "^4.1.2"
},
"dependencies": {
"@types/d3": "^5.7.1",
"@types/d3": "^6.2.0",
"@types/plotly.js": "^1.54.2",
"@types/rx": "^4.1.1",
"d3": "^5.9.2",
"d3-axis": "^1.0.12",
"d3-brush": "^1.0.6",
"d3-drag": "^1.2.3",
"d3-path": "^1.0.7",
"d3-scale": "^3.0.0",
"d3-selection": "^1.4.0",
"parcel-bundler": "^1.12.3",
"rxjs": "^6.4.0",
"tslint": "^5.15.0"
"d3": "^6.2.0",
"d3-axis": "^2.0.0",
"d3-brush": "^2.1.0",
"d3-drag": "^2.0.0",
"d3-path": "^2.0.0",
"d3-scale": "^3.2.3",
"d3-selection": "^2.0.0",
"parcel-bundler": "^1.12.4",
"plotly.js-dist": "^1.57.1",
"rxjs": "^6.5.4",
"tslint": "^5.20.1"
}
}
import Plotly, { Layout, Data } from "plotly.js-dist";
import { Selection } from "d3-selection";
import { max, group, extent } from "d3-array";
import { format } from "d3-format";
import { ScaleSequential, scaleSequential } from "d3-scale";
import { interpolatePlasma } from "d3-scale-chromatic";
import { GenomeScanData, SignificanceThreshold } from "../../types";
export default function () {
function genomeScan(_selection: Selection<HTMLDivElement, GenomeScanData, any, any>, legendClickCallback: (event: Plotly.LegendClickEvent) => boolean, legendDoubleClickCallback: (event: Plotly.LegendClickEvent) => boolean) {
const threholdFormat = format(".2f");
_selection.each(function ({ lod_score_per_chromosome, significance_thresholds }: GenomeScanData) {
const container = this;
if (container) {
const maxLodScoreStr = max(lod_score_per_chromosome, d => d.lod);
if (maxLodScoreStr) {
const thresholdColor = scaleSequential(interpolatePlasma).domain([80, 100])
// const thresholdColor = scaleLinear<string, string>().domain([80, 100]).range(["red", "blue"])
const maxLodScore = maxLodScoreStr;
const chrDatasMap = group(lod_score_per_chromosome, d => d.chr);
const chrDatas = Array.from(chrDatasMap, ([key, values]) => ({ key, values }))
const chrCount = chrDatas.length;
let traces = chrDatas.map((dataPerChr, i): Data => {
const j = i + 1;
return {
type: "scattergl",
xaxis: `x${j}`,
yaxis: "y",
name: "chr " + dataPerChr.key,
mode: "lines",
x: dataPerChr.values.map(d => {
return d.pos
}),
y: dataPerChr.values.map(d => d.lod),
text: dataPerChr.values.map(d => d.marker),
}
});
for (const thresholdPartialTrace of thresholdInterval(significance_thresholds, maxLodScore, thresholdColor)) {
const tresholdTraces = chrDatas.map((dataPerChr, i): Data => {
const j = i + 1;
const [min, max] = extent(dataPerChr.values.map(d => {
return d.pos
}))
if (typeof min !== "undefined" && typeof max != "undefined") {
let to = min
return {
type: "scattergl",
xaxis: `x${j}`,
yaxis: "y",
name: `Significance ${thresholdPartialTrace.significance}% (${threholdFormat(thresholdPartialTrace.threshold)})`,
mode: "lines",
legendgroup: `${thresholdPartialTrace.significance}`,
showlegend: i === 0 ? true : false,
x: [min, max],
y: [thresholdPartialTrace.threshold, thresholdPartialTrace.threshold],
line: {
dash: "dot",
color: thresholdPartialTrace.color
},
text: ["80%", "80%"],
}
}
else {
return {
type: "scattergl",
xaxis: `x${j}`,
yaxis: "y",
name: "threholds" + dataPerChr.key,
mode: "lines",
x: [0, 1],
y: [4.5, 4.5],
text: ["80%", "80%"],
}
}
})
traces = [...traces, ...tresholdTraces]
}
const layout: Partial<Layout> & { grid: { rows: number, columns: number, pattern: string } } = {
height: 800,
showlegend: true,
grid: {
rows: 1,
columns: chrCount,
pattern: 'coupled',
},
autosize: true,
}
Array.from(chrDatas).forEach((curr, i) => {
const xaxisIndex: string = (i === 0) ? "" : (i + 1).toString();
const xaxisKey = "xaxis" + xaxisIndex;
// @ts-ignore
layout[xaxisKey] = {
title: curr.key,
type: "category",
showticklabels: false,
showgrid: false,
zeroline: false,
}
});
const yaxis = layout.yaxis;
layout.yaxis = {
...yaxis,
title: "LOD score",
}
Plotly.react(container, traces, layout, { responsive: true, autosizable: true }).then(function (root) {
console.log(root);
root.removeAllListeners('plotly_legendclick')
root.removeAllListeners('plotly_legenddoubleclick')
root.on('plotly_legenddoubleclick', legendDoubleClickCallback)
root.on('plotly_legendclick', legendClickCallback)
})
}
}
})
}
function thresholdInterval(significanceThresholds: SignificanceThreshold[], max: number, colorScale: ScaleSequential<string>) {
const significanceThresholdsLength = significanceThresholds.length;
return significanceThresholds.map((st, i, arr) => {
return {
...st,
y0: st.threshold,
y1: (i < significanceThresholdsLength - 1) ? arr[i + 1].threshold : max,
color: colorScale(st.significance)
}
})
}
return genomeScan;
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment