Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 35 additions & 0 deletions public/test_data/run1.B1phi1.i1.seqwish.w1/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[
{
"Accession": "1727",
"Release_Date": "2020-01-13T00:00:00Z",
"Species": "Severe acute respiratory syndrome-related coronavirus",
"Length": 29903,
"Geo_Location": "China",
"Host": "Homo sapiens",
"Isolation_Source": "",
"Collection_Date": "2019-12",
"GenBank_Title": "Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, complete genome"
},
{
"Accession": "2103",
"Release_Date": "2020-03-17T00:00:00Z",
"Species": "Severe acute respiratory syndrome-related coronavirus",
"Length": 29611,
"Geo_Location": "Spain",
"Host": "Homo sapiens",
"Isolation_Source": "oronasopharynx",
"Collection_Date": "2020-03-08",
"GenBank_Title": "Severe acute respiratory syndrome coronavirus 2 isolate SARS-CoV-2/Valencia001/human/2020/ESP, partial genome"
},
{
"Accession": "1925",
"Release_Date": "2020-03-17T00:00:00Z",
"Species": "Severe acute respiratory syndrome-related coronavirus",
"Length": 29611,
"Geo_Location": "Spain",
"Host": "Homo sapiens",
"Isolation_Source": "oronasopharynx",
"Collection_Date": "2020-03-04",
"GenBank_Title": "Severe acute respiratory syndrome coronavirus 2 isolate SARS-CoV-2/Valencia002/human/2020/ESP, partial genome"
}
]
5 changes: 5 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class App extends Component {
"useWidthCompression",
this.recalcXLayout.bind(this)
);
observe(
this.props.store,
"colorByGeo",
this.recalcY.bind(this)
);
observe(this.props.store, "useConnector", this.recalcXLayout.bind(this));
observe(
this.props.store,
Expand Down
3 changes: 3 additions & 0 deletions src/ComponentConnectorRect.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export class MatrixCell extends React.Component {
tooltipContent += "," + start + "-" + end;
}
}
if (this.props.store.metaData.get(this.props.pathName) !== undefined) {
tooltipContent += " ; " + this.props.store.metaData.get(this.props.pathName).Geo_Location;
}
this.props.store.updateCellTooltipContent(tooltipContent); //item[2] is array of ranges
}

Expand Down
27 changes: 24 additions & 3 deletions src/ComponentRect.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ const zip = (arr, ...arrs) => {
return arr.map((val, i) => arrs.reduce((a, arr) => [...a, arr[i]], [val]));
};

function colorFromStr(colorKey) {
colorKey = colorKey.toString();
let hash = 0;
for (let i = 0; i < colorKey.length; i++) {
hash = colorKey.charCodeAt(i) + ((hash << 5) - hash);
}
let colour = "#";
for (let j = 0; j < 3; j++) {
let value = (hash >> (j * 8)) & 0xff;
colour += ("00" + value.toString(16)).substr(-2);
}
return colour;
}

export function compress_visible_rows(components) {
/*Returns a Map with key of the original row number and value of the new, compressed row number.
* Use this for y values of occupancy and LinkColumn cells. */
Expand Down Expand Up @@ -80,7 +94,14 @@ class ComponentRect extends React.Component {
}
this_y = this.props.compressed_row_mapping[row_n];
}

let pathName = this.props.pathNames[row_n];
let rowColor = "#838383"
if (this.props.store.colorByGeo && this.props.store.metaData) {
let metaData = this.props.store.metaData;
if (metaData.get(pathName) !== undefined) {
rowColor = colorFromStr(metaData.get(pathName).Geo_Location);
}
}
return row.map((cell, x) => {
if (cell.length) {
return (
Expand All @@ -89,7 +110,7 @@ class ComponentRect extends React.Component {
key={"occupant" + row_n + x}
item={cell}
store={this.props.store}
pathName={this.props.pathNames[row_n]}
pathName={pathName}
x={x_val + x * this.props.store.pixelsPerColumn}
y={
this_y * this.props.store.pixelsPerRow +
Expand All @@ -98,7 +119,7 @@ class ComponentRect extends React.Component {
row_number={row_n}
width={width}
height={this.props.store.pixelsPerRow}
color={"#838383"}
color={rowColor}
/>
</>
);
Expand Down
25 changes: 25 additions & 0 deletions src/ControlHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ class ControlHeader extends React.Component {
) : (
<></>
)}
<span>
{" "}
Color by Provenance:
<ColorGeoSwitch store={this.props.store} />
</span>
<span>
{" "}
Row Height:
Expand Down Expand Up @@ -281,4 +286,24 @@ WidthCompressedViewSwitch.propTypes = {
store: PropTypes.object,
};

class ColorGeoSwitch extends React.Component {
render() {
return (
<Observer>
{() => (
<input
type="checkbox"
checked={this.props.store.colorByGeo}
onChange={this.props.store.toggleColorByGeo}
/>
)}
</Observer>
);
}
}

ColorGeoSwitch.propTypes = {
store: PropTypes.object,
};

export default ControlHeader;
29 changes: 29 additions & 0 deletions src/PangenomeSchematic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import { observe } from "mobx";
import { urlExists } from "./URL";

class PangenomeSchematic extends React.Component {
constructor(props) {
Expand All @@ -11,13 +12,17 @@ class PangenomeSchematic extends React.Component {
this.pathNames = [];
this.components = [];
this.nucleotides = [];
this.metadata = [];

this.loadIndexFile(this.props.store.jsonName) //initializes this.chunk_index
.then(() => this.jsonFetch(this.props.store.getChunkURLs()[0]))
.then(this.loadFirstJSON.bind(this));
this.loadMetadataFile(this.props.store.jsonName);

//whenever jsonName changes,
observe(this.props.store, "jsonName", () => {
this.loadIndexFile(this.props.store.jsonName);
this.loadMetadataFile(this.props.store.jsonName);
});
// console.log("public ", process.env.PUBLIC_URL ) //PUBLIC_URL is empty
}
Expand Down Expand Up @@ -151,6 +156,30 @@ class PangenomeSchematic extends React.Component {
return;
});
}
loadMetadataFile(jsonFilename) {
const mdataPath = `${process.env.PUBLIC_URL}/test_data/${this.props.store.jsonName}/metadata.json`;
if (urlExists(mdataPath)) {
console.log("Reading", mdataPath);
return fetch(mdataPath)
.then((res) => res.json())
.then((json) => {
var metaData = {};
// commented-out could be used further to read in the metadata categories
// into json_entries array.
//let json_entries = [];
for (let i=0; i<json.length; i++) {
metaData[json[i][this.props.store.metaDataKey]] = json[i];
// if (i == 0) {
// for (let [key, value] of Object.entries(json[0])) {
// json_entries.push(key);
// }
// this.props.store.setMetaDataChoices(json_entries);
// }
}
this.props.store.setMetaData(metaData);
});
}
}
processArray() {
/*parses beginBin to endBin range, returns false if new file needed*/
if (!this.jsonData) {
Expand Down
35 changes: 35 additions & 0 deletions src/ViewportInputsStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,27 @@ const PathNucPos = types.model("PathNucPos", {
nucPos: types.integer,
});

const metaDataModelEntry = types.model({
Accession: types.identifier,
Release_Date: types.string,
Species: types.string,
Length: types.integer,
Geo_Location: types.string,
Host: types.string,
Isolation_Source: types.string,
Collection_Date: types.string,
GenBank_Title: types.string
});


export let RootStore; // AG: why is it exported?
RootStore = types
.model({
useVerticalCompression: false,
useWidthCompression: false,
binScalingFactor: 3,
useConnector: true,
colorByGeo: false,
beginEndBin: BeginEndBin,
pixelsPerColumn: 10,
pixelsPerRow: 7,
Expand All @@ -30,6 +44,9 @@ RootStore = types
pathIndexServerAddress: "http://193.196.29.24:3010/",
binWidth: 100,
nucleotideHeight: 10,
metaDataKey: "Accession",
metaData: types.map(metaDataModelEntry),
//metaDataChoices: types.array(types.string)
})
.actions((self) => {
function updateBeginEndBin(newBegin, newEnd) {
Expand Down Expand Up @@ -92,6 +109,9 @@ RootStore = types
function updateWidth(event) {
self.pixelsPerColumn = Number(event.target.value);
}
function toggleColorByGeo() {
self.colorByGeo = !self.colorByGeo;
}
function tryJSONpath(event) {
const url =
process.env.PUBLIC_URL +
Expand Down Expand Up @@ -140,6 +160,17 @@ RootStore = types
function setBinWidth(binWidth) {
self.binWidth = binWidth;
}
function setMetaData(metadata) {
for (let [key, value] of Object.entries(metadata)) {
self.metaData.set(key, value);
}
}
function getMetaData(key) {
self.metaData.get(key);
}
function setMetaDataChoices(ar) {
self.metaDataChoices = ar;
}
return {
updateBeginEndBin,
updateTopOffset,
Expand All @@ -153,6 +184,7 @@ RootStore = types
toggleUseConnector,
updateHeight,
updateWidth,
toggleColorByGeo,
tryJSONpath,
switchChunkURLs,
getChunkURLs,
Expand All @@ -164,6 +196,9 @@ RootStore = types
getPathNucPos,
updatePathNucPos,
setBinWidth,
setMetaData,
getMetaData,
setMetaDataChoices
};
})
.views((self) => ({}));
Expand Down